2007-03-29 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TreeView.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004-2005 Novell, Inc.
21 //
22 // Authors:
23 //      Jackson Harper (jackson@ximian.com)
24 //      Kazuki Oikawa (kazuki@panicode.com)
25
26 using System;
27 using System.Collections;
28 using System.ComponentModel;
29 using System.ComponentModel.Design;
30 using System.Drawing;
31 using System.Drawing.Drawing2D;
32 using System.Runtime.InteropServices;
33
34 namespace System.Windows.Forms {
35         [DefaultProperty("Nodes")]
36         [DefaultEvent("AfterSelect")]
37         [Designer("System.Windows.Forms.Design.TreeViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
38         public class TreeView : Control {
39                 #region Fields
40                 private string path_separator = "\\";
41                 private int item_height = -1;
42                 private bool sorted;
43                 internal TreeNode root_node;
44                 internal bool nodes_added;
45                 private TreeNodeCollection nodes;
46
47                 private TreeViewAction selection_action;
48                 private TreeNode selected_node;
49                 private TreeNode pre_selected_node;
50                 private TreeNode focused_node;
51                 private TreeNode highlighted_node;
52                 private Rectangle mouse_rect;
53                 private bool select_mmove;
54
55                 private ImageList image_list;
56                 private int image_index = -1;
57                 private int selected_image_index = -1;
58
59 #if NET_2_0
60                 private string image_key;
61                 private string selected_image_key;
62 #endif
63                 private bool full_row_select;
64                 private bool hot_tracking;
65                 private int indent = 19;
66
67                 private NodeLabelEditEventArgs edit_args;
68                 private LabelEditTextBox edit_text_box;
69                 internal TreeNode edit_node;
70                 
71                 private bool checkboxes;
72                 private bool label_edit;
73                 private bool scrollable = true;
74                 private bool show_lines = true;
75                 private bool show_root_lines = true;
76                 private bool show_plus_minus = true;
77                 private bool hide_selection = true;
78
79                 private int max_visible_order = -1;
80                 private VScrollBar vbar;
81                 private HScrollBar hbar;
82                 private bool vbar_bounds_set;
83                 private bool hbar_bounds_set;
84                 internal int skipped_nodes;
85                 internal int hbar_offset;
86                 
87                 private int update_stack;
88                 private bool update_needed;
89                 
90                 private Pen dash;
91                 private Color line_color;
92                 private StringFormat string_format;
93
94                 private int drag_begin_x = 0;
95                 private int drag_begin_y = 0;
96                 private long handle_count = 1;
97
98                 private TreeViewDrawMode draw_mode;
99
100 #if NET_2_0
101                 IComparer tree_view_node_sorter;
102 #endif
103                 #endregion      // Fields
104
105                 #region Public Constructors     
106                 public TreeView ()
107                 {
108                         border_style = BorderStyle.Fixed3D;
109                         base.background_color = ThemeEngine.Current.ColorWindow;
110                         base.foreground_color = ThemeEngine.Current.ColorWindowText;
111
112                         root_node = new TreeNode (this);
113                         root_node.Text = "ROOT NODE";
114                         nodes = new TreeNodeCollection (root_node);
115                         root_node.SetNodes (nodes);
116
117                         MouseDown += new MouseEventHandler (MouseDownHandler);
118                         MouseUp += new MouseEventHandler(MouseUpHandler);
119                         MouseMove += new MouseEventHandler(MouseMoveHandler);
120                         SizeChanged += new EventHandler (SizeChangedHandler);
121                         FontChanged += new EventHandler (FontChangedHandler);
122                         LostFocus += new EventHandler (LostFocusHandler);
123                         GotFocus += new EventHandler (GotFocusHandler);
124                         MouseWheel += new MouseEventHandler(MouseWheelHandler);
125                         VisibleChanged += new EventHandler (VisibleChangedHandler);
126
127                         SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
128 #if NET_2_0
129                                 | ControlStyles.UseTextForAccessibility
130 #endif
131                                 , false);
132
133                         string_format = new StringFormat ();
134                         string_format.LineAlignment = StringAlignment.Center;
135                         string_format.Alignment = StringAlignment.Center;
136
137                         vbar = new ImplicitVScrollBar ();
138                         hbar = new ImplicitHScrollBar ();
139
140                         vbar.Visible = false;
141                         hbar.Visible = false;
142                         vbar.ValueChanged += new EventHandler (VScrollBarValueChanged);
143                         hbar.ValueChanged += new EventHandler (HScrollBarValueChanged);
144
145                         SuspendLayout ();
146                         Controls.AddImplicit (vbar);
147                         Controls.AddImplicit (hbar);
148                         ResumeLayout ();
149                 }
150
151                 #endregion      // Public Constructors
152
153                 #region Public Instance Properties
154                 public override Color BackColor {
155                         get { return base.BackColor;}
156                         set {
157                                 base.BackColor = value;
158
159                                 CreateDashPen ();
160                                 Invalidate ();
161                         }
162                 }
163
164
165                 [Browsable(false)]
166                 [EditorBrowsable(EditorBrowsableState.Never)]
167                 public override Image BackgroundImage {
168                         get { return base.BackgroundImage; }
169                         set { base.BackgroundImage = value; }
170                 }
171
172                 [DefaultValue(BorderStyle.Fixed3D)]
173                 [DispId(-504)]
174                 public BorderStyle BorderStyle {
175                         get { return InternalBorderStyle; }
176                         set { InternalBorderStyle  = value; }
177                 }
178
179                 [DefaultValue(false)]
180                 public bool CheckBoxes {
181                         get { return checkboxes; }
182                         set {
183                                 if (value == checkboxes)
184                                         return;
185                                 checkboxes = value;
186
187                                 // Match a "bug" in the MS implementation where disabling checkboxes
188                                 // collapses the entire tree, but enabling them does not affect the
189                                 // state of the tree.
190                                 if (!checkboxes)
191                                         root_node.CollapseAllUncheck ();
192
193                                 Invalidate ();
194                         }
195                 }
196
197                 public override Color ForeColor {
198                         get { return base.ForeColor; }
199                         set { base.ForeColor = value; }
200                 }
201                 [DefaultValue(false)]
202                 public bool FullRowSelect {
203                         get { return full_row_select; }
204                         set {
205                                 if (value == full_row_select)
206                                         return;
207                                 full_row_select = value;
208                                 Invalidate ();
209                         }
210                 }
211                 [DefaultValue(true)]
212                 public bool HideSelection {
213                         get { return hide_selection; }
214                         set {
215                                 if (hide_selection == value)
216                                         return;
217                                 hide_selection = value;
218                                 Invalidate ();
219                         }
220                 }
221
222                 [DefaultValue(false)]
223                 public bool HotTracking {
224                         get { return hot_tracking; }
225                         set { hot_tracking = value; }
226                 }
227
228                 [DefaultValue(0)]
229                 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
230                 [Localizable(true)]
231                 [TypeConverter(typeof(TreeViewImageIndexConverter))]
232                 public int ImageIndex {
233                         get { return image_index; }
234                         set {
235                                 if (value < -1) {
236                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
237                                                 "'value' must be greater than or equal to 0.");
238                                 }
239                                 if (image_index == value)
240                                         return;
241                                 image_index = value;
242                                 Invalidate ();
243                         }
244                 }
245
246                 [DefaultValue(null)]
247                 public ImageList ImageList {
248                         get { return image_list; }
249                         set {
250                                 image_list = value;
251                                 Invalidate ();
252                         }
253                 }
254
255                 [Localizable(true)]
256                 public int Indent {
257                         get { return indent; }
258                         set {
259                                 if (indent == value)
260                                         return;
261                                 if (value > 32000) {
262                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
263                                                 "'Indent' must be less than or equal to 32000");
264                                 }       
265                                 if (value < 0) {
266                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
267                                                 "'Indent' must be greater than or equal to 0.");
268                                 }
269                                 indent = value;
270                                 Invalidate ();
271                         }
272                 }
273
274                 [Localizable(true)]
275                 public int ItemHeight {
276                         get {
277                                 if (item_height == -1)
278                                         return FontHeight + 3;
279                                 return item_height;
280                         }
281                         set {
282                                 if (value == item_height)
283                                         return;
284                                 item_height = value;
285                                 Invalidate ();
286                         }
287                 }
288
289                 internal int ActualItemHeight {
290                         get {
291                                 int res = ItemHeight;
292                                 if (ImageList != null && ImageList.ImageSize.Height > res)
293                                         res = ImageList.ImageSize.Height;
294                                 return res;
295                         }
296                 }
297
298                 [DefaultValue(false)]
299                 public bool LabelEdit {
300                         get { return label_edit; }
301                         set { label_edit = value; }
302                 }
303
304                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
305                 [MergableProperty(false)]
306                 [Localizable(true)]
307                 public TreeNodeCollection Nodes {
308                         get { return nodes; }
309                 }
310
311                 [DefaultValue("\\")]
312                 public string PathSeparator {
313                         get { return path_separator; }
314                         set { path_separator = value; }
315                 }
316
317                 [DefaultValue(true)]
318                 public bool Scrollable {
319                         get { return scrollable; }
320                         set {
321                                 if (scrollable == value)
322                                         return;
323                                 scrollable = value;
324                                 UpdateScrollBars ();
325                         }
326                 }
327
328                 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
329                 [TypeConverter(typeof(TreeViewImageIndexConverter))]
330                 [Localizable(true)]
331                 [DefaultValue(0)]
332                 public int SelectedImageIndex {
333                         get { return selected_image_index; }
334                         set {
335                                 if (value < -1) {
336                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
337                                                 "'value' must be greater than or equal to 0.");
338                                 }
339                                 UpdateNode (SelectedNode);
340                         }
341                 }
342
343                 [Browsable(false)]
344                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
345                 public TreeNode SelectedNode {
346                         get {
347                                 if (!IsHandleCreated)
348                                         return pre_selected_node;
349                                 return selected_node;
350                         }
351                         set {
352                                 if (!IsHandleCreated) {
353                                         pre_selected_node = value;
354                                         return;
355                                 }
356
357                                 if (selected_node == value) {
358                                         selection_action = TreeViewAction.Unknown;
359                                         return;
360                                 }
361
362                                 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (value, false, selection_action);
363                                 OnBeforeSelect (e);
364
365                                 if (e.Cancel)
366                                         return;
367
368                                 Rectangle invalid = Rectangle.Empty;
369
370                                 if (selected_node != null) {
371                                         invalid = Bloat (selected_node.Bounds);
372                                 }
373                                 if (focused_node != null) {
374                                         invalid = Rectangle.Union (invalid,
375                                                         Bloat (focused_node.Bounds));
376                                 }
377
378                                 if (value != null)
379                                         invalid = Rectangle.Union (invalid, Bloat (value.Bounds));
380
381                                 highlighted_node = value;
382                                 selected_node = value;
383                                 focused_node = value;
384
385                                 if (full_row_select || draw_mode != TreeViewDrawMode.Normal) {
386                                         invalid.X = 0;
387                                         invalid.Width = ViewportRectangle.Width;
388                                 }
389
390                                 if (invalid != Rectangle.Empty)
391                                         Invalidate (invalid);
392
393                                 // We ensure its visible after we update because
394                                 // scrolling is used for insure visible
395                                 if (selected_node != null)
396                                         selected_node.EnsureVisible ();
397
398                                 OnAfterSelect (new TreeViewEventArgs (value, TreeViewAction.Unknown));
399                                 selection_action = TreeViewAction.Unknown;
400                         }
401                 }
402
403                 private Rectangle Bloat (Rectangle rect)
404                 {
405                         rect.Y--;
406                         rect.X--;
407                         rect.Height += 2;
408                         rect.Width += 2;
409                         return rect;
410                 }
411
412                 [DefaultValue(true)]
413                 public bool ShowLines {
414                         get { return show_lines; }
415                         set {
416                                 if (show_lines == value)
417                                         return;
418                                 show_lines = value;
419                                 Invalidate ();
420                         }
421                 }
422
423                 [DefaultValue(true)]
424                 public bool ShowPlusMinus {
425                         get { return show_plus_minus; }
426                         set {
427                                 if (show_plus_minus == value)
428                                         return;
429                                 show_plus_minus = value;
430                                 Invalidate ();
431                         }
432                 }
433
434                 [DefaultValue(true)]
435                 public bool ShowRootLines {
436                         get { return show_root_lines; }
437                         set {
438                                 if (show_root_lines == value)
439                                         return;
440                                 show_root_lines = value;
441                                 Invalidate ();
442                         }
443                 }
444
445                 [DefaultValue(false)]
446                 public bool Sorted {
447                         get { return sorted; }
448                         set {
449 #if NET_2_0
450                                 if (sorted == value)
451                                         return;
452                                 sorted = value;
453                                 //LAMESPEC: The documentation says that setting this to true should sort alphabetically if TreeViewNodeSorter is set.
454                                 // There seems to be a bug in the Microsoft implementation.
455                                 if (sorted && tree_view_node_sorter == null) {
456                                         Sort (null);
457                                 }
458 #else
459                                 if (sorted != value)
460                                         sorted = value;
461                                 if (sorted) {
462                                         Sort (null);
463                                 }
464 #endif
465                         }
466                 }
467
468                 [Browsable(false)]
469                 [EditorBrowsable(EditorBrowsableState.Never)]
470                 [Bindable(false)]
471                 public override string Text {
472                         get { return base.Text; }
473                         set { base.Text = value; }
474                 }
475
476                 [Browsable(false)]
477                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
478                 public TreeNode TopNode {
479                         get {
480                                 if (root_node.FirstNode == null)
481                                         return null;
482                                 OpenTreeNodeEnumerator one = new OpenTreeNodeEnumerator (root_node.FirstNode);
483                                 one.MoveNext ();
484                                 for (int i = 0; i < skipped_nodes; i++)
485                                         one.MoveNext ();
486                                 return one.CurrentNode;
487                         }
488 #if NET_2_0
489                         set {
490                                 SetTop (value);
491                         }
492 #endif
493                 }
494
495 #if NET_2_0
496                 public IComparer TreeViewNodeSorter {
497                         get {
498                                 return tree_view_node_sorter;
499                         }
500                         set {
501                                 tree_view_node_sorter = value;
502                                 if (tree_view_node_sorter != null) {
503                                         Sort();
504                                         //LAMESPEC: The documentation says that setting this should set Sorted to false.
505                                         // There seems to be a bug in the Microsoft implementation.
506                                         sorted = true;
507                                 }
508                         }
509                 }
510 #endif
511
512                 [Browsable(false)]
513                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
514                 public int VisibleCount {
515                         get {
516                                 return ViewportRectangle.Height / ActualItemHeight;
517                         }
518                 }
519
520 #if NET_2_0
521                 /// According to MSDN this property has no effect on the treeview
522                 protected override bool DoubleBuffered {
523                         get { return true; }
524                         set { /* whatever */ }
525                 }
526 #endif
527
528 #if NET_2_0
529                 public
530 #else
531                 private
532 #endif
533                 Color LineColor {
534                         get {
535                                 if (line_color == Color.Empty) {
536                                         Color res = ControlPaint.Dark (BackColor);
537                                         if (res == BackColor)
538                                                 res = ControlPaint.Light (BackColor);
539                                         return res;
540                                 }
541                                 return line_color;
542                         }
543                         set {
544                                 line_color = value;
545                                 if (show_lines) {
546                                         CreateDashPen ();
547                                         Invalidate ();
548                                 }
549                         }
550                 }
551 #if NET_2_0
552                 [Localizable (true)]
553                 public string ImageKey {
554                         get { return image_key; }
555                         set {
556                                 if (image_key == value)
557                                         return;
558                                 image_index = -1;
559                                 image_key = value;
560                                 Invalidate ();
561                         }
562                 }
563
564                 public string SelectedImageKey {
565                         get { return selected_image_key; }
566                         set {
567                                 if (selected_image_key == value)
568                                         return;
569                                 selected_image_index = -1;
570                                 selected_image_key = value;
571                                 UpdateNode (SelectedNode);
572                         }
573                 }
574 #endif
575
576 #if NET_2_0
577                 public override ImageLayout BackgroundImageLayout {
578                         get { return base.BackgroundImageLayout; }
579                         set { base.BackgroundImageLayout = value; }
580                 }
581 #endif
582
583 #if NET_2_0
584                 public TreeViewDrawMode DrawMode {
585                         get { return draw_mode; }
586                         set { draw_mode = value; }
587                 }
588 #endif
589                 #endregion      // Public Instance Properties
590
591                 #region Protected Instance Properties
592                 protected override CreateParams CreateParams {
593                         get {
594                                 CreateParams cp = base.CreateParams;
595                                 return cp;
596                         }
597                 }
598
599                 protected override Size DefaultSize {
600                         get { return new Size (121, 97); }
601                 }
602
603                 #endregion      // Protected Instance Properties
604
605                 #region Public Instance Methods
606                 public void BeginUpdate ()
607                 {
608                         update_stack++;
609                 }
610
611                 public void EndUpdate ()
612                 {
613                         if (update_stack > 1) {
614                                 update_stack--;
615                         } else {
616                                 update_stack = 0;
617                                 if (update_needed) {
618                                         RecalculateVisibleOrder (root_node);
619                                         UpdateScrollBars ();
620                                         //      if (SelectedNode != null)
621                                         //              SelectedNode.EnsureVisible ();
622                                         Invalidate (ViewportRectangle);
623                                         update_needed = false;
624                                 }
625                         }
626                 }
627
628 #if NET_2_0
629                 public
630 #else
631                 private
632 #endif
633                 void Sort ()
634                 {
635 #if NET_2_0
636                         Sort (Nodes.Count >= 2 ? tree_view_node_sorter : null);
637 #else
638                         Sort (null);
639 #endif
640                 }
641
642                 void Sort (IComparer sorter) 
643                 {
644                         Nodes.Sort (sorter);
645                         RecalculateVisibleOrder (root_node);
646                         UpdateScrollBars ();
647                         Invalidate ();
648                 }
649
650                 public void ExpandAll ()
651                 {
652                         BeginUpdate ();
653                         root_node.ExpandAll ();
654
655                         EndUpdate ();
656
657                         ///
658                         /// Everything below this is basically an emulation of a strange bug on MS
659                         /// where they don't always scroll to the last node on ExpandAll
660                         ///
661 #if NET_2_0
662                         if (!IsHandleCreated)
663                                 return;
664 #endif
665                         
666                         bool found = false;
667                         foreach (TreeNode child in Nodes) {
668                                 if (child.Nodes.Count > 0)
669                                         found = true;
670                         }
671                         
672                         if (!found)
673                                 return;
674
675                         // Walk all the way to the end, then walk back visible count
676                         //to find the new top node
677                         OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (root_node);
678                         while (walk.MoveNext ())
679                         { }
680
681                         SetTop (walk.CurrentNode);
682                 }
683
684                 
685                 public void CollapseAll ()
686                 {
687                         TreeNode walk = TopNode;
688                         
689                         while (walk.parent != root_node)
690                                 walk = walk.parent;
691
692                         BeginUpdate ();
693                         root_node.CollapseAll ();
694                         EndUpdate ();
695
696                         SetTop (walk);
697                 }
698
699                 public TreeNode GetNodeAt (Point pt) {
700                         return GetNodeAt (pt.Y);
701                 }
702
703                 public TreeNode GetNodeAt (int x, int y)
704                 {
705                         return GetNodeAt (y);
706                 }
707
708                 private TreeNode GetNodeAtUseX (int x, int y) {
709                         TreeNode node = GetNodeAt (y);
710                         if (node == null || !(IsTextArea (node, x) || full_row_select))
711                                 return null;
712                         return node;
713                                         
714                 }
715
716                 public int GetNodeCount (bool include_subtrees) {
717                         return root_node.GetNodeCount (include_subtrees);
718                 }
719
720                 public override string ToString () {
721                         int count = Nodes.Count;
722                         if (count <= 0)
723                                 return String.Concat (base.ToString (), "Node Count: 0");
724                         return String.Concat (base.ToString (), "Node Count: ", count, " Nodes[0]: ", Nodes [0]);
725                                                 
726                 }
727
728                 #endregion      // Public Instance Methods
729
730                 #region Protected Instance Methods
731                 protected override void CreateHandle () {
732                         base.CreateHandle ();
733                         RecalculateVisibleOrder (root_node);
734                         UpdateScrollBars ();
735
736                         if (pre_selected_node != null)
737                                 SelectedNode = pre_selected_node;
738                 }
739
740                 protected override void Dispose (bool disposing) {
741                         if (disposing)
742                                 image_list = null;
743
744                         base.Dispose (disposing);
745                 }
746
747                 protected OwnerDrawPropertyBag GetItemRenderStyles (TreeNode node, int state) {
748                         return node.prop_bag;
749                 }
750
751                 protected override bool IsInputKey (Keys key_data)
752                 {
753                         if ((key_data & Keys.Alt) == 0) {
754                                 switch (key_data & Keys.KeyCode) {
755                                 case Keys.Enter:
756                                 case Keys.Escape:
757                                 case Keys.Prior:
758                                 case Keys.Next:
759                                 case Keys.End:
760                                 case Keys.Home:
761                                 case Keys.Left:
762                                 case Keys.Up:
763                                 case Keys.Right:
764                                 case Keys.Down:
765                                         return true;
766                                 }
767                         }
768                         return base.IsInputKey (key_data);
769                 }
770
771                 protected override void OnKeyDown (KeyEventArgs e)
772                 {
773                         OpenTreeNodeEnumerator ne;
774
775                         switch (e.KeyData & Keys.KeyCode) {
776                         case Keys.Add:
777                                 if (selected_node != null && selected_node.IsExpanded)
778                                         selected_node.Expand ();
779                                 break;
780                         case Keys.Subtract:
781                                 if (selected_node != null && selected_node.IsExpanded)
782                                         selected_node.Collapse ();
783                                 break;
784                         case Keys.Left:
785                                 if (selected_node != null) {
786                                         if (selected_node.IsExpanded)
787                                                 selected_node.Collapse ();
788                                         else {
789                                                 TreeNode parent = selected_node.Parent;
790                                                 if (parent != null) {
791                                                         selection_action = TreeViewAction.ByKeyboard;
792                                                         SelectedNode = parent;
793                                                 }
794                                         }
795                                 }
796                                 break;
797                         case Keys.Right:
798                                 if (selected_node != null) {
799                                         if (!selected_node.IsExpanded)
800                                                 selected_node.Expand ();
801                                         else {
802                                                 TreeNode child = selected_node.FirstNode;
803                                                 if (child != null)
804                                                         SelectedNode = child;
805                                         }
806                                 }
807                                 break;
808                         case Keys.Up:
809                                 if (selected_node != null) {
810                                         ne = new OpenTreeNodeEnumerator (selected_node);
811                                         if (ne.MovePrevious () && ne.MovePrevious ()) {
812                                                 selection_action = TreeViewAction.ByKeyboard;
813                                                 SelectedNode = ne.CurrentNode;
814                                         }
815                                 }
816                                 break;
817                         case Keys.Down:
818                                 if (selected_node != null) {
819                                         ne = new OpenTreeNodeEnumerator (selected_node);
820                                         if (ne.MoveNext () && ne.MoveNext ()) {
821                                                 selection_action = TreeViewAction.ByKeyboard;
822                                                 SelectedNode = ne.CurrentNode;
823                                         }
824                                 }
825                                 break;
826                         case Keys.Home:
827                                 if (root_node.Nodes.Count > 0) {
828                                         ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]);
829                                         if (ne.MoveNext ()) {
830                                                 selection_action = TreeViewAction.ByKeyboard;
831                                                 SelectedNode = ne.CurrentNode;
832                                         }
833                                 }
834                                 break;
835                         case Keys.End:
836                                 if (root_node.Nodes.Count > 0) {
837                                         ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]);
838                                         while (ne.MoveNext ())
839                                         { }
840                                         selection_action = TreeViewAction.ByKeyboard;
841                                         SelectedNode = ne.CurrentNode;
842                                 }
843                                 break;
844                         case Keys.PageDown:
845                                 if (selected_node != null) {
846                                         ne = new OpenTreeNodeEnumerator (selected_node);
847                                         int move = VisibleCount;
848                                         for (int i = 0; i < move && ne.MoveNext (); i++) {
849                                                 
850                                         }
851                                         selection_action = TreeViewAction.ByKeyboard;
852                                         SelectedNode = ne.CurrentNode;
853                                 }
854                                 break;
855                         case Keys.PageUp:
856                                 if (selected_node != null) {
857                                         ne = new OpenTreeNodeEnumerator (selected_node);
858                                         int move = VisibleCount;
859                                         for (int i = 0; i < move && ne.MovePrevious (); i++)
860                                         { }
861                                         selection_action = TreeViewAction.ByKeyboard;
862                                         SelectedNode = ne.CurrentNode;
863                                 }
864                                 break;
865                         case Keys.Multiply:
866                                 if (selected_node != null)
867                                         selected_node.ExpandAll ();
868                                 break;
869                         }
870                         base.OnKeyDown (e);
871
872                         if (!e.Handled && checkboxes &&
873                              selected_node != null &&
874                             (e.KeyData & Keys.KeyCode) == Keys.Space) {
875                                 selected_node.check_reason = TreeViewAction.ByKeyboard;
876                                 selected_node.Checked = !selected_node.Checked;         
877                                 e.Handled = true;
878                         }
879                 }
880
881                 protected override void OnKeyPress (KeyPressEventArgs e)
882                 {
883                         base.OnKeyPress (e);
884                         if (e.KeyChar == ' ')
885                                 e.Handled = true;
886                 }
887
888                 protected override void OnKeyUp (KeyEventArgs e)
889                 {
890                         base.OnKeyUp (e);
891                         if ((e.KeyData & Keys.KeyCode) == Keys.Space)
892                                 e.Handled = true;
893                 }
894
895                 protected virtual void OnItemDrag (ItemDragEventArgs e)
896                 {
897                         ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
898                         if (eh != null)
899                                 eh (this, e);
900                 }
901
902 #if NET_2_0
903                 protected virtual void OnDrawNode(DrawTreeNodeEventArgs e) {
904                         DrawTreeNodeEventHandler eh = (DrawTreeNodeEventHandler)(Events[DrawNodeEvent]);
905                         if (eh != null)
906                                 eh(this, e);
907                 }
908 #endif
909
910                 protected internal virtual void OnAfterCheck (TreeViewEventArgs e) {
911                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterCheckEvent]);
912                         if (eh != null)
913                                 eh (this, e);
914                 }
915
916                 protected internal virtual void OnAfterCollapse (TreeViewEventArgs e) {
917                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterCollapseEvent]);
918                         if (eh != null)
919                                 eh (this, e);
920                 }
921
922                 protected internal virtual void OnAfterExpand (TreeViewEventArgs e) {
923                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterExpandEvent]);
924                         if (eh != null)
925                                 eh (this, e);
926                 }
927
928                 protected virtual void OnAfterLabelEdit (NodeLabelEditEventArgs e) {
929                         NodeLabelEditEventHandler eh = (NodeLabelEditEventHandler)(Events [AfterLabelEditEvent]);
930                         if (eh != null)
931                                 eh (this, e);
932                 }
933
934                 protected virtual void OnAfterSelect (TreeViewEventArgs e) {
935                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterSelectEvent]);
936                         if (eh != null)
937                                 eh (this, e);
938                 }
939
940                 protected internal virtual void OnBeforeCheck (TreeViewCancelEventArgs e) {
941                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeCheckEvent]);
942                         if (eh != null)
943                                 eh (this, e);
944                 }
945
946                 protected internal virtual void OnBeforeCollapse (TreeViewCancelEventArgs e) {
947                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeCollapseEvent]);
948                         if (eh != null)
949                                 eh (this, e);
950                 }
951
952                 protected internal virtual void OnBeforeExpand (TreeViewCancelEventArgs e) {
953                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeExpandEvent]);
954                         if (eh != null)
955                                 eh (this, e);
956                 }
957
958                 protected virtual void OnBeforeLabelEdit (NodeLabelEditEventArgs e) {
959                         NodeLabelEditEventHandler eh = (NodeLabelEditEventHandler)(Events [BeforeLabelEditEvent]);
960                         if (eh != null)
961                                 eh (this, e);
962                 }
963
964                 protected virtual void OnBeforeSelect (TreeViewCancelEventArgs e) {
965                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeSelectEvent]);
966                         if (eh != null)
967                                 eh (this, e);
968                 }
969
970                 protected override void OnHandleCreated (EventArgs e) {
971                         base.OnHandleCreated (e);
972                 }
973
974                 protected override void OnHandleDestroyed (EventArgs e) {
975                         base.OnHandleDestroyed (e);
976                 }
977
978                 protected override void WndProc(ref Message m) {
979                         switch ((Msg) m.Msg) {
980
981                         case Msg.WM_LBUTTONDBLCLK:
982                                 int val = m.LParam.ToInt32();
983                                 DoubleClickHandler (null, new
984                                                 MouseEventArgs (MouseButtons.Left,
985                                                                 2, val & 0xffff,
986                                                                 (val>>16) & 0xffff, 0));
987                                         break;
988                         }
989                         base.WndProc (ref m);
990                 }
991
992                 #endregion      // Protected Instance Methods
993
994                 #region Internal & Private Methods and Properties
995                 internal IntPtr CreateNodeHandle ()
996                 {
997                         return (IntPtr) handle_count++;
998                 }
999
1000                 internal TreeNode NodeFromHandle (IntPtr handle)
1001                 {
1002                         // This method is called rarely, so instead of maintaining a table
1003                         // we just walk the tree nodes to find the matching handle
1004                         return NodeFromHandleRecursive (root_node,  handle);
1005                 }
1006
1007                 private TreeNode NodeFromHandleRecursive (TreeNode node, IntPtr handle)
1008                 {
1009                         if (node.handle == handle)
1010                                 return node;
1011                         foreach (TreeNode child in node.Nodes) {
1012                                 TreeNode match = NodeFromHandleRecursive (child, handle);
1013                                 if (match != null)
1014                                         return match;
1015                         }
1016                         return null;
1017                 }
1018
1019                 internal Rectangle ViewportRectangle {
1020                         get {
1021                                 Rectangle res = ClientRectangle;
1022
1023                                 if (vbar != null && vbar.Visible)
1024                                         res.Width -= vbar.Width;
1025                                 if (hbar != null && hbar.Visible)
1026                                         res.Height -= hbar.Height;
1027                                 return res;
1028                         }
1029                 }
1030
1031                 private TreeNode GetNodeAt (int y)
1032                 {
1033                         if (nodes.Count <= 0)
1034                                 return null;
1035
1036                         OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (TopNode);
1037                         int move = y / ActualItemHeight;
1038                         for (int i = -1; i < move; i++) {
1039                                 if (!o.MoveNext ())
1040                                         return null;
1041                         }
1042
1043                         return o.CurrentNode;
1044                 }
1045
1046                 private bool IsTextArea (TreeNode node, int x)
1047                 {
1048                         return node != null && node.Bounds.Left <= x && node.Bounds.Right >= x;
1049                 }
1050
1051                 private bool IsSelectableArea (TreeNode node, int x)
1052                 {
1053                         if (node == null)
1054                                 return false;
1055                         int l = node.Bounds.Left;
1056                         if (ImageList != null)
1057                                 l -= ImageList.ImageSize.Width;
1058                         return l <= x && node.Bounds.Right >= x;
1059                                 
1060                 }
1061
1062                 private bool IsPlusMinusArea (TreeNode node, int x)
1063                 {
1064                         if (node.Nodes.Count == 0 || (node.parent == root_node && !show_root_lines))
1065                                 return false;
1066
1067                         int l = node.Bounds.Left + 5;
1068
1069                         if (show_root_lines || node.Parent != null)
1070                                 l -= indent;
1071                         if (ImageList != null)
1072                                 l -= ImageList.ImageSize.Width + 3;
1073                         if (checkboxes)
1074                                 l -= 19;
1075                         return (x > l && x < l + 8);
1076                 }
1077
1078                 private bool IsCheckboxArea (TreeNode node, int x)
1079                 {
1080                         int l = CheckBoxLeft (node);
1081                         return (x > l && x < l + 10);
1082                 }
1083
1084                 private int CheckBoxLeft (TreeNode node)
1085                 {
1086                         int l = node.Bounds.Left + 5;
1087
1088                         if (show_root_lines || node.Parent != null)
1089                                 l -= indent;
1090                         if (ImageList != null)
1091                                 l -= ImageList.ImageSize.Width + 3;
1092
1093                         return l;
1094                 }
1095
1096                 internal void RecalculateVisibleOrder (TreeNode start)
1097                 {
1098                         if (update_stack > 0)
1099                                 return;
1100
1101                         int order;
1102                         if (start == null) {
1103                                 start = root_node;
1104                                 order = 0;
1105                         } else
1106                                 order = start.visible_order;
1107
1108                         
1109                         
1110                         OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (start);
1111                         while (walk.MoveNext ()) {
1112                                 walk.CurrentNode.visible_order = order;
1113                                 order++;
1114                         }
1115
1116                         max_visible_order = order;
1117                 }
1118
1119                 internal void SetTop (TreeNode node)
1120                 {
1121                         if (!vbar.is_visible) {
1122                                 skipped_nodes = node.visible_order;
1123                                 return;
1124                         }
1125
1126                         vbar.Value = Math.Min (node.visible_order, vbar.Maximum - VisibleCount);
1127                 }
1128
1129                 internal void SetBottom (TreeNode node)
1130                 {
1131                         if (!vbar.is_visible)
1132                                 return;
1133
1134                         OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (node);
1135
1136                         int bottom = ViewportRectangle.Bottom;
1137                         int offset = 0;
1138                         while (walk.MovePrevious ()) {
1139                                 if (walk.CurrentNode.Bounds.Bottom <= bottom)
1140                                         break;
1141                                 offset++;
1142                         }
1143
1144                         int nv = vbar.Value + offset;
1145                         if (vbar.Value + offset < vbar.Maximum) {
1146                                 vbar.Value = nv;
1147                         } else {
1148 #if DEBUG
1149                                 Console.Error.WriteLine ("setting bottom to value greater then maximum ({0}, {1})",
1150                                                 nv, vbar.Maximum);
1151 #endif
1152                         }
1153                                 
1154                 }
1155
1156                 internal void UpdateBelow (TreeNode node)
1157                 {
1158                         if (update_stack > 0) {
1159                                 update_needed = true;
1160                                 return;
1161                         }
1162
1163                         if (node == root_node) {
1164                                 Invalidate (ViewportRectangle);
1165                                 return;
1166                         }
1167                                 
1168                         // We need to update the current node so the plus/minus block gets update too
1169                         int top = Math.Max (node.Bounds.Top - 1, 0);
1170                         Rectangle invalid = new Rectangle (0, top,
1171                                         Width, Height - top);
1172                         Invalidate (invalid);
1173                 }
1174
1175                 internal void UpdateNode (TreeNode node)
1176                 {
1177                         if (node == null)
1178                                 return;
1179
1180                         if (update_stack > 0) {
1181                                 update_needed = true;
1182                                 return;
1183                         }
1184
1185                         if (node == root_node) {
1186                                 Invalidate ();
1187                                 return;
1188                         }
1189
1190                         Rectangle invalid = new Rectangle (0, node.Bounds.Top - 1, Width,
1191                                         node.Bounds.Height + 1);
1192                         Invalidate (invalid);
1193                 }
1194
1195                 internal void UpdateNodePlusMinus (TreeNode node)
1196                 {
1197                         if (update_stack > 0) {
1198                                 update_needed = true;
1199                                 return;
1200                         }
1201
1202                         int l = node.Bounds.Left + 5;
1203
1204                         if (show_root_lines || node.Parent != null)
1205                                 l -= indent;
1206                         if (ImageList != null)
1207                                 l -= ImageList.ImageSize.Width + 3;
1208                         if (checkboxes)
1209                                 l -= 19;
1210
1211                         Invalidate (new Rectangle (l, node.Bounds.Top, 8, node.Bounds.Height));
1212                 }
1213
1214                 internal override void OnPaintInternal (PaintEventArgs pe)
1215                 {
1216                         Draw (pe.ClipRectangle, pe.Graphics);
1217                 }
1218
1219                 internal void CreateDashPen ()
1220                 {
1221                         dash = new Pen (LineColor, 1);
1222                         dash.DashStyle = DashStyle.Dot;
1223                 }
1224
1225                 private void Draw (Rectangle clip, Graphics dc)
1226                 {
1227                         dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), clip);
1228
1229                         if (dash == null)
1230                                 CreateDashPen ();
1231
1232                         Rectangle viewport = ViewportRectangle;
1233                         Rectangle original_clip = clip;
1234                         if (clip.Bottom > viewport.Bottom)
1235                                 clip.Height = viewport.Bottom - clip.Top;
1236
1237                         OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (TopNode);
1238                         while (walk.MoveNext ()) {
1239                                 TreeNode current = walk.CurrentNode;
1240
1241                                 // Haven't gotten to visible nodes yet
1242                                 if (current.GetY () + ActualItemHeight < clip.Top)
1243                                         continue;
1244
1245                                 // Past the visible nodes
1246                                 if (current.GetY () > clip.Bottom)
1247                                         break;
1248
1249                                 DrawTreeNode (current, dc, clip);
1250                         }
1251
1252                         if (hbar.Visible && vbar.Visible) {
1253                                 Rectangle corner = new Rectangle (hbar.Right, vbar.Bottom, vbar.Width, hbar.Height);
1254                                 if (original_clip.IntersectsWith (corner))
1255                                         dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorControl),
1256                                                         corner);
1257                         }
1258                 }
1259
1260                 private void DrawNodePlusMinus (TreeNode node, Graphics dc, int x, int middle)
1261                 {
1262                         dc.DrawRectangle (SystemPens.ControlDarkDark, x, middle - 4, 8, 8);
1263
1264                         if (node.IsExpanded) {
1265                                 dc.DrawLine (SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle); 
1266                         } else {
1267                                 dc.DrawLine (SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle);
1268                                 dc.DrawLine (SystemPens.ControlDarkDark, x + 4, middle - 2, x + 4, middle + 2);
1269                         }
1270                 }
1271
1272                 private void DrawNodeCheckBox (TreeNode node, Graphics dc, int x, int middle)
1273                 {
1274                         Pen pen = ThemeEngine.Current.ResPool.GetSizedPen(Color.Black, 2);
1275                                 dc.DrawRectangle (pen, x + 3, middle - 4, 11, 11);
1276
1277                         if (node.Checked) {
1278                                 Pen check_pen = ThemeEngine.Current.ResPool.GetPen(Color.Black);
1279                                 
1280                                 int check_size = 5;
1281                                 int lineWidth = 3;
1282                                 
1283                                 Rectangle rect = new Rectangle (x + 5, middle - 2, check_size, check_size);
1284                                 
1285                                 for (int i = 0; i < lineWidth; i++) {
1286                                         dc.DrawLine (check_pen, rect.Left + 1, rect.Top + lineWidth + i, rect.Left + 3, rect.Top + 5 + i);
1287                                         dc.DrawLine (check_pen, rect.Left + 3, rect.Top + 5 + i, rect.Left + 7, rect.Top + 1 + i);
1288                                 }
1289                         }
1290                 }
1291
1292                 private void DrawNodeLines (TreeNode node, Graphics dc, Rectangle clip, Pen dash, int x, int y, int middle)
1293                 {
1294                         int ladjust = 9;
1295                         int radjust = 0;
1296
1297                         if (node.nodes.Count > 0 && show_plus_minus)
1298                                 ladjust = 13;
1299                         if (checkboxes)
1300                                 radjust = 3;
1301
1302                         dc.DrawLine (dash, x - indent + ladjust, middle, x + radjust, middle);
1303
1304                         if (node.PrevNode != null || node.Parent != null) {
1305                                 ladjust = 9;
1306                                 dc.DrawLine (dash, x - indent + ladjust, node.Bounds.Top,
1307                                                 x - indent + ladjust, middle - (show_plus_minus && node.Nodes.Count > 0 ? 4 : 0));
1308                         }
1309
1310                         if (node.NextNode != null) {
1311                                 ladjust = 9;
1312                                 dc.DrawLine (dash, x - indent + ladjust, middle + (show_plus_minus && node.Nodes.Count > 0 ? 4 : 0),
1313                                                 x - indent + ladjust, node.Bounds.Bottom);
1314                                 
1315                         }
1316
1317                         ladjust = 0;
1318                         if (show_plus_minus)
1319                                 ladjust = 9;
1320                         TreeNode parent = node.Parent;
1321                         while (parent != null) {
1322                                 if (parent.NextNode != null) {
1323                                         int px = parent.GetLinesX () - indent + ladjust;
1324                                         dc.DrawLine (dash, px, node.Bounds.Top, px, node.Bounds.Bottom);
1325                                 }
1326                                 parent = parent.Parent;
1327                         }
1328                 }
1329
1330                 private void DrawNodeImage (TreeNode node, Graphics dc, Rectangle clip, int x, int y)
1331                 {
1332                         // Rectangle r = new Rectangle (x, y + 2, ImageList.ImageSize.Width, ImageList.ImageSize.Height);
1333
1334                         if (!RectsIntersect (clip, x, y, ImageList.ImageSize.Width, ImageList.ImageSize.Height))
1335                                 return;
1336
1337                         if (ImageList == null)
1338                                 return;
1339
1340                         int use_index = -1;
1341
1342                         if (!node.IsSelected) {
1343                                 if (node.ImageIndex > -1 && node.ImageIndex < ImageList.Images.Count) {
1344                                         use_index = node.ImageIndex;
1345                                 } else if (ImageIndex > -1 && ImageIndex < ImageList.Images.Count) {
1346                                         use_index = ImageIndex;
1347                                 }
1348                         } else {
1349                                 if (node.SelectedImageIndex > -1 && node.SelectedImageIndex < ImageList.Images.Count) {
1350                                         use_index = node.SelectedImageIndex;
1351                                 } else if (SelectedImageIndex > -1 && SelectedImageIndex < ImageList.Images.Count) {
1352                                         use_index = SelectedImageIndex;
1353                                 }
1354                         }
1355
1356 #if NET_2_0
1357
1358                         if (!node.IsSelected) {
1359                                 if (use_index == -1 && !String.IsNullOrEmpty (node.ImageKey)) {
1360                                         use_index = image_list.Images.IndexOfKey (node.ImageKey);
1361                                 }
1362
1363                                 if (use_index == -1 && !String.IsNullOrEmpty (ImageKey)) {
1364                                         use_index = image_list.Images.IndexOfKey (ImageKey);
1365                                 }
1366                         } else {
1367                                 if (use_index == -1 && !String.IsNullOrEmpty (node.SelectedImageKey)) {
1368                                         use_index = image_list.Images.IndexOfKey (node.SelectedImageKey);
1369                                 }
1370
1371                                 if (use_index == -1 && !String.IsNullOrEmpty (SelectedImageKey)) {
1372                                         use_index = image_list.Images.IndexOfKey (SelectedImageKey);
1373                                 }
1374                         }
1375 #endif
1376
1377                         if (use_index == -1 && ImageList.Images.Count > 0) {
1378                                 use_index = 0;
1379                         }
1380
1381                         if (use_index != -1) {
1382                                 ImageList.Draw (dc, x, y, ImageList.ImageSize.Width, 
1383                                                 ImageList.ImageSize.Height, use_index);
1384                         }
1385                 }
1386
1387                 private void LabelEditFinished (object sender, EventArgs e)
1388                 {
1389                         EndEdit (edit_node);
1390                 }
1391
1392                 internal void BeginEdit (TreeNode node)
1393                 {
1394                         if (edit_node != null)
1395                                 EndEdit (edit_node);
1396
1397                         if (edit_text_box == null) {
1398                                 edit_text_box = new LabelEditTextBox ();
1399                                 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
1400                                 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
1401                                 Controls.Add (edit_text_box);
1402                         }
1403
1404                         edit_text_box.Bounds = node.Bounds;
1405                         edit_text_box.Width += 4;
1406
1407                         edit_text_box.Text = node.Text;
1408                         edit_text_box.Visible = true;
1409                         edit_text_box.Focus ();
1410                         edit_text_box.SelectAll ();
1411
1412                         edit_args = new NodeLabelEditEventArgs (edit_node);
1413                         OnBeforeLabelEdit (edit_args);
1414
1415                         if (edit_args.CancelEdit)
1416                                 EndEdit (node);
1417                         
1418                         edit_node = node;
1419                 }
1420
1421                 internal void EndEdit (TreeNode node)
1422                 {
1423                         if (edit_text_box != null && edit_text_box.Visible) {
1424                                 edit_text_box.Visible = false;
1425                         }
1426
1427                         if (edit_node != null && edit_node == node) {
1428                                 OnAfterLabelEdit (edit_args);
1429
1430                                 if (!edit_args.CancelEdit) {
1431                                         if (edit_args.Label != null)
1432                                                 edit_node.Text = edit_args.Label;
1433                                         else
1434                                                 edit_node.Text = edit_text_box.Text;
1435                                 }
1436
1437                         }
1438
1439                         
1440                         edit_node = null;
1441                         UpdateNode (node);
1442                 }
1443
1444                 internal int GetNodeWidth (TreeNode node)
1445                 {
1446                         Font font = node.NodeFont;
1447                         if (node.NodeFont == null)
1448                                 font = Font;
1449                         return (int) DeviceContext.MeasureString (node.Text, font, 0, string_format).Width + 3;
1450                 }
1451
1452                 private void DrawSelectionAndFocus(TreeNode node, Graphics dc, Rectangle r)
1453                 {
1454                         if (Focused && focused_node == node) {
1455                                 ControlPaint.DrawFocusRectangle (dc, r, ForeColor, BackColor);
1456                         }
1457                         if (draw_mode != TreeViewDrawMode.Normal)
1458                                 return;
1459
1460                         r.Inflate (-1, -1);
1461                         if (Focused && node == highlighted_node) {
1462                                 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), r);
1463                         } else if (!hide_selection && node == highlighted_node) {
1464                                 dc.FillRectangle (SystemBrushes.Control, r);
1465                         } else {
1466                                 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (node.BackColor), r);
1467                         }
1468                 }
1469                  
1470                 private void DrawStaticNode (TreeNode node, Graphics dc)
1471                 {
1472                         if (!full_row_select)
1473                                 DrawSelectionAndFocus(node, dc, node.Bounds);
1474
1475                         
1476                         Font font = node.NodeFont;
1477                         if (node.NodeFont == null)
1478                                 font = Font;
1479                         Color text_color = (Focused && node == highlighted_node ?
1480                                         ThemeEngine.Current.ColorHighlightText : node.ForeColor);
1481                         if (text_color.IsEmpty)
1482                                 text_color = ForeColor;
1483                         dc.DrawString (node.Text, font,
1484                                         ThemeEngine.Current.ResPool.GetSolidBrush (text_color),
1485                                         node.Bounds, string_format);
1486                 }
1487
1488                 private void DrawTreeNode (TreeNode node, Graphics dc, Rectangle clip)
1489                 {
1490                         int child_count = node.nodes.Count;
1491                         int y = node.GetY ();
1492                         int middle = y + (ActualItemHeight / 2);
1493
1494                         if (full_row_select) {
1495                                 Rectangle r = new Rectangle (1, y + 2, ViewportRectangle.Width - 2, ActualItemHeight);
1496                                 DrawSelectionAndFocus (node, dc, r);
1497                         }
1498
1499                         if (draw_mode == TreeViewDrawMode.Normal || draw_mode == TreeViewDrawMode.OwnerDrawText) {
1500                                 if ((show_root_lines || node.Parent != null) && show_plus_minus && child_count > 0)
1501                                         DrawNodePlusMinus (node, dc, node.GetLinesX () - Indent + 5, middle);
1502
1503                                 if (checkboxes)
1504                                         DrawNodeCheckBox (node, dc, CheckBoxLeft (node) - 3, middle);
1505
1506                                 if (show_lines)
1507                                         DrawNodeLines (node, dc, clip, dash, node.GetLinesX (), y, middle);
1508
1509                                 if (ImageList != null)
1510                                         DrawNodeImage (node, dc, clip, node.GetImageX (), y);
1511                         }
1512
1513                         
1514 #if NET_2_0
1515                         if (draw_mode != TreeViewDrawMode.Normal) {
1516                                 dc.FillRectangle (Brushes.White, node.Bounds);
1517                                 TreeNodeStates tree_node_state = TreeNodeStates.Default;;
1518                                 if (node.IsSelected)
1519                                         tree_node_state = TreeNodeStates.Selected;
1520                                 if (node.Checked)
1521                                         tree_node_state |= TreeNodeStates.Checked;
1522                                 if (node == focused_node)
1523                                         tree_node_state |= TreeNodeStates.Focused;
1524                                 Rectangle node_bounds = node.Bounds;
1525                                 if (draw_mode == TreeViewDrawMode.OwnerDrawText) {
1526                                         node_bounds.X += 3;
1527                                         node_bounds.Y += 1;
1528                                 } else {
1529                                         node_bounds.X = 0;
1530                                         node_bounds.Width = Width;
1531                                 }
1532
1533                                 DrawTreeNodeEventArgs e = new DrawTreeNodeEventArgs (dc, node, node_bounds, tree_node_state);
1534
1535                                 OnDrawNode (e);                         
1536                                 if (!e.DrawDefault)
1537                                         return;
1538                         }
1539 #endif
1540
1541                         if (!node.IsEditing)
1542                                 DrawStaticNode (node, dc);
1543                 }
1544
1545                 internal void UpdateScrollBars ()
1546                 {
1547                         if (IsDisposed || update_stack > 0 || !IsHandleCreated || !Visible)
1548                                 return;
1549
1550                         bool vert = false;
1551                         bool horz = false;
1552                         int height = -1;
1553                         int width = -1;
1554
1555                         if (scrollable) {
1556                                 OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (root_node);
1557                                 
1558                                 while (walk.MoveNext ()) {
1559                                         int r = walk.CurrentNode.Bounds.Right;
1560                                         int b = walk.CurrentNode.Bounds.Bottom;
1561
1562                                         if (r > width)
1563                                                 width = r;
1564                                         if (b > height)
1565                                                 height = b;
1566                                 }
1567
1568                                 // Remove scroll adjustments
1569                                 if (nodes.Count > 0)
1570                                         height -= nodes [0].Bounds.Top;
1571                                 width += hbar_offset;
1572
1573                                 if (height > ClientRectangle.Height) {
1574                                         vert = true;
1575
1576                                         if (width > ClientRectangle.Width - SystemInformation.VerticalScrollBarWidth)
1577                                                 horz = true;
1578                                 } else if (width > ClientRectangle.Width) {
1579                                         horz = true;
1580                                 }
1581
1582                                 if (!vert && horz && height > ClientRectangle.Height - SystemInformation.HorizontalScrollBarHeight)
1583                                         vert = true;
1584                         }
1585
1586                         if (vert) {
1587                                 int visible_height = horz ? ClientRectangle.Height - hbar.Height : ClientRectangle.Height;
1588                                 vbar.SetValues (Math.Max (0, max_visible_order - 2), visible_height / ActualItemHeight);
1589                                 /*
1590                                 vbar.Maximum = max_visible_order;
1591                                 vbar.LargeChange = ClientRectangle.Height / ItemHeight;
1592                                 */
1593
1594                                 if (!vbar_bounds_set) {
1595                                         vbar.Bounds = new Rectangle (ClientRectangle.Width - vbar.Width, 0, vbar.Width,
1596                                                         ClientRectangle.Height -
1597                                                         (horz ? SystemInformation.VerticalScrollBarWidth : 0));
1598                                         vbar_bounds_set = true;
1599
1600                                         // We need to recalc the hbar if the vbar is now visible
1601                                         hbar_bounds_set = false;
1602                                 }
1603
1604                                 
1605                                 vbar.Visible = true;
1606                                 if (skipped_nodes > 0) {
1607                                         int skip = Math.Min (skipped_nodes, vbar.Maximum - VisibleCount);
1608                                         skipped_nodes = 0;
1609                                         vbar.Value = skip;
1610                                         skipped_nodes = skip;
1611                                 }
1612                         } else {
1613                                 skipped_nodes = 0;
1614                                 RecalculateVisibleOrder (root_node);
1615                                 vbar.Visible = false;
1616                                 vbar_bounds_set = false;
1617                         }
1618
1619                         if (horz) {
1620                                 hbar.SetValues (width + 1, ClientRectangle.Width - (vert ? SystemInformation.VerticalScrollBarWidth : 0));
1621                                 /*
1622                                 hbar.LargeChange = ClientRectangle.Width;
1623                                 hbar.Maximum = width + 1;
1624                                 */
1625
1626                                 if (!hbar_bounds_set) {
1627                                         hbar.Bounds = new Rectangle (0, ClientRectangle.Height - hbar.Height,
1628                                                         ClientRectangle.Width - (vert ? SystemInformation.VerticalScrollBarWidth : 0),
1629                                                         hbar.Height);
1630                                         hbar_bounds_set = true;
1631                                 }
1632                                 hbar.Visible = true;
1633                         } else {
1634                                 hbar_offset = 0;
1635                                 hbar.Visible = false;
1636                                 hbar_bounds_set = false;
1637                         }
1638                 }
1639
1640                 private void SizeChangedHandler (object sender, EventArgs e)
1641                 {
1642                         if (IsHandleCreated) {
1643                                 if (max_visible_order == -1)
1644                                         RecalculateVisibleOrder (root_node);
1645                                 UpdateScrollBars ();
1646                         }
1647
1648                         if (vbar.Visible) {
1649                                 vbar.Bounds = new Rectangle (ClientRectangle.Width - vbar.Width, 0, vbar.Width,
1650                                                 ClientRectangle.Height - (hbar.Visible ? SystemInformation.HorizontalScrollBarHeight : 0));
1651                         }
1652
1653                         if (hbar.Visible) {
1654                                 hbar.Bounds = new Rectangle (0, ClientRectangle.Height - hbar.Height,
1655                                                 ClientRectangle.Width - (vbar.Visible ? SystemInformation.VerticalScrollBarWidth : 0), hbar.Height);
1656                         }
1657                 }
1658
1659                 private void VScrollBarValueChanged (object sender, EventArgs e)
1660                 {
1661                         EndEdit (edit_node);
1662
1663                         SetVScrollPos (vbar.Value, null);
1664                 }
1665
1666                 private void SetVScrollPos (int pos, TreeNode new_top)
1667                 {
1668                         if (pos < 0)
1669                                 pos = 0;
1670
1671                         if (skipped_nodes == pos)
1672                                 return;
1673
1674                         int diff = skipped_nodes - pos;
1675                         skipped_nodes = pos;
1676
1677                         int y_move = diff * ActualItemHeight;
1678                         XplatUI.ScrollWindow (Handle, ViewportRectangle, 0, y_move, false);
1679                 }
1680
1681                 private void SetVScrollTop (TreeNode new_top)
1682                 {
1683                         vbar.Value = new_top.visible_order - VisibleCount;
1684                 }
1685
1686                 private void HScrollBarValueChanged(object sender, EventArgs e)
1687                 {
1688                         EndEdit (edit_node);
1689
1690                         int old_offset = hbar_offset;
1691                         hbar_offset = hbar.Value;
1692
1693                         if (hbar_offset < 0) {
1694                                 hbar_offset = 0;
1695                         }
1696
1697                         XplatUI.ScrollWindow (Handle, ViewportRectangle, old_offset - hbar_offset, 0, false);
1698                 }
1699
1700                 internal void ExpandBelow (TreeNode node, int count_to_next)
1701                 {
1702                         if (update_stack > 0) {
1703                                 update_needed = true;
1704                                 return;
1705                         }
1706
1707                         Rectangle below = new Rectangle (0, node.Bounds.Bottom, ViewportRectangle.Width,
1708                                         ViewportRectangle.Height - node.Bounds.Bottom);
1709
1710                         int amount = count_to_next * ActualItemHeight;
1711
1712                         if (amount > 0)
1713                                 XplatUI.ScrollWindow (Handle, below, 0, amount, false);
1714
1715                         if (show_plus_minus) {
1716                                 Invalidate (new Rectangle (0, node.GetY (), Width, ActualItemHeight));
1717                         }
1718                 }
1719
1720                 internal void CollapseBelow (TreeNode node, int count_to_next)
1721                 {
1722                         if (update_stack > 0) {
1723                                 update_needed = true;
1724                                 return;
1725                         }
1726
1727                         Rectangle below = new Rectangle (0, node.Bounds.Bottom, ViewportRectangle.Width,
1728                                         ViewportRectangle.Height - node.Bounds.Bottom);
1729
1730                         int amount = count_to_next * ActualItemHeight;
1731
1732                         if (amount > 0)
1733                                 XplatUI.ScrollWindow (Handle, below, 0, -amount, false);
1734
1735                         if (show_plus_minus) {
1736                                 Invalidate (new Rectangle (0, node.GetY (), Width, ActualItemHeight));
1737                         }
1738                 }
1739
1740                 private void MouseWheelHandler(object sender, MouseEventArgs e) {
1741
1742                         if (vbar == null || !vbar.is_visible) {
1743                                 return;
1744                         }
1745
1746                         if (e.Delta < 0) {
1747                                 vbar.Value = Math.Min(vbar.Value + SystemInformation.MouseWheelScrollLines, vbar.Maximum - VisibleCount + 1);
1748                         } else {
1749                                 vbar.Value = Math.Max(0, vbar.Value - SystemInformation.MouseWheelScrollLines);
1750                         }
1751                 }
1752
1753                 private void VisibleChangedHandler (object sender, EventArgs e)
1754                 {
1755                         if (Visible) {
1756                                 UpdateScrollBars ();
1757                         }
1758                 }
1759
1760                 private void FontChangedHandler (object sender, EventArgs e)
1761                 {
1762                         if (IsHandleCreated) {
1763                                 TreeNode top = TopNode;
1764                                 InvalidateNodeWidthRecursive (root_node);
1765
1766                                 SetTop (top);
1767                         }
1768                 }
1769
1770                 private void InvalidateNodeWidthRecursive (TreeNode node)
1771                 {
1772                         node.InvalidateWidth ();
1773                         foreach (TreeNode child in node.Nodes) {
1774                                 InvalidateNodeWidthRecursive (child);
1775                         }
1776                 }
1777
1778                 private void GotFocusHandler (object sender, EventArgs e)
1779                 {
1780                         if (selected_node == null && pre_selected_node != null)
1781                                 SelectedNode = pre_selected_node;
1782                         else if (selected_node != null)
1783                                 UpdateNode (selected_node);
1784                 }
1785
1786                 private void LostFocusHandler (object sender, EventArgs e)
1787                 {
1788                         UpdateNode (SelectedNode);
1789                 }
1790
1791                 private void MouseDownHandler (object sender, MouseEventArgs e)
1792                 {
1793                         if (e.Button == MouseButtons.Right)
1794                                 Focus ();
1795
1796                         TreeNode node = GetNodeAt (e.Y);
1797                         if (node == null)
1798                                 return;
1799
1800                         if (show_plus_minus && IsPlusMinusArea (node, e.X)) {
1801                                 node.Toggle ();
1802                                 return;
1803                         } else if (checkboxes && IsCheckboxArea (node, e.X)) {
1804                                 node.check_reason = TreeViewAction.ByMouse;
1805                                 node.Checked = !node.Checked;
1806                                 UpdateNode(node);
1807                                 return;
1808                         } else if (IsSelectableArea (node, e.X) || full_row_select) {
1809                                 TreeNode old_highlighted = highlighted_node;
1810                                 highlighted_node = node;
1811                                 if (label_edit && e.Clicks == 1 && highlighted_node == old_highlighted) {
1812                                         BeginEdit (node);
1813                                 } else if (highlighted_node != focused_node) {
1814                                         Size ds = SystemInformation.DragSize;
1815                                         mouse_rect.X = e.X - ds.Width;
1816                                         mouse_rect.Y = e.Y - ds.Height;
1817                                         mouse_rect.Width = ds.Width * 2;
1818                                         mouse_rect.Height = ds.Height * 2;
1819
1820                                         select_mmove = true;
1821                                 }
1822
1823                                 Invalidate (highlighted_node.Bounds);
1824                                 if (old_highlighted != null)
1825                                         Invalidate (Bloat (old_highlighted.Bounds));
1826                         } 
1827                 }
1828
1829                 private void MouseUpHandler (object sender, MouseEventArgs e) {
1830
1831                         drag_begin_x = -1;
1832                         drag_begin_y = -1;
1833
1834                         if (!select_mmove)
1835                                 return;
1836
1837                         if (e.Button == MouseButtons.Right) {
1838                                 Invalidate (highlighted_node.Bounds);
1839                                 highlighted_node = selected_node;
1840                                 Invalidate (selected_node.Bounds);
1841                         }
1842                         select_mmove = false;
1843
1844                         TreeViewCancelEventArgs ce = new TreeViewCancelEventArgs (highlighted_node, false, TreeViewAction.ByMouse);
1845                         OnBeforeSelect (ce);
1846
1847                         Rectangle invalid;
1848                         if (!ce.Cancel) {
1849                                 TreeNode prev_focused_node = focused_node;
1850                                 TreeNode prev_highlighted_node = highlighted_node;
1851                                 
1852                                 selected_node = highlighted_node;
1853                                 focused_node = highlighted_node;
1854                                 OnAfterSelect (new TreeViewEventArgs (selected_node, TreeViewAction.ByMouse));
1855
1856                                 if (prev_focused_node != null) {
1857                                         invalid = Rectangle.Union (Bloat (prev_focused_node.Bounds),
1858                                                         Bloat (prev_highlighted_node.Bounds));
1859                                 } else {
1860                                         invalid = Bloat (prev_highlighted_node.Bounds);
1861                                 }
1862
1863                                 Invalidate (invalid);
1864                         } else {
1865                                 highlighted_node = focused_node;
1866                                 selected_node = focused_node;
1867                         }
1868                 }
1869
1870                 private void MouseMoveHandler (object sender, MouseEventArgs e) {
1871
1872                         if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right) {
1873                                 if (drag_begin_x == -1 && drag_begin_y == -1) {
1874                                         drag_begin_x = e.X;
1875                                         drag_begin_y = e.Y;
1876                                 } else {
1877                                         double rise = Math.Pow (drag_begin_x - e.X, 2);
1878                                         double run = Math.Pow (drag_begin_y - e.Y, 2);
1879                                         double move = Math.Sqrt (rise + run);
1880                                         if (move > 3) {
1881                                                 TreeNode drag = GetNodeAtUseX (e.X, e.Y);
1882                                                 
1883                                                 if (drag != null) {
1884                                                         OnItemDrag (new ItemDragEventArgs (e.Button, drag));
1885                                                 }
1886                                                 drag_begin_x = -1;
1887                                                 drag_begin_y = -1;
1888                                         }
1889                                 }
1890                                 
1891                         }
1892
1893                         // If there is enough movement before the mouse comes up,
1894                         // selection is reverted back to the originally selected node
1895                         if (!select_mmove || mouse_rect.Contains (e.X, e.Y))
1896                                 return;
1897
1898                         Invalidate (highlighted_node.Bounds);
1899                         Invalidate (selected_node.Bounds);
1900                         Invalidate (focused_node.Bounds);
1901
1902                         highlighted_node = selected_node;
1903                         focused_node = selected_node;
1904
1905                         select_mmove = false;
1906                 }
1907
1908                 private void DoubleClickHandler (object sender, MouseEventArgs e) {
1909                         TreeNode node = GetNodeAtUseX (e.X,e.Y);
1910                         if(node != null) {
1911                                 node.Toggle();
1912                         }
1913                 }
1914
1915                 
1916                 private bool RectsIntersect (Rectangle r, int left, int top, int width, int height)
1917                 {
1918                         return !((r.Left > left + width) || (r.Right < left) ||
1919                                         (r.Top > top + height) || (r.Bottom < top));
1920                 }
1921
1922                 #endregion      // Internal & Private Methods and Properties
1923
1924                 #region Events
1925                 static object ItemDragEvent = new object ();
1926                 static object AfterCheckEvent = new object ();
1927                 static object AfterCollapseEvent = new object ();
1928                 static object AfterExpandEvent = new object ();
1929                 static object AfterLabelEditEvent = new object ();
1930                 static object AfterSelectEvent = new object ();
1931                 static object BeforeCheckEvent = new object ();
1932                 static object BeforeCollapseEvent = new object ();
1933                 static object BeforeExpandEvent = new object ();
1934                 static object BeforeLabelEditEvent = new object ();
1935                 static object BeforeSelectEvent = new object ();
1936 #if NET_2_0
1937                 static object DrawNodeEvent = new object ();
1938                 static object NodeMouseClickEvent = new object ();
1939                 static object NodeMouseDoubleClickEvent = new object();
1940 #endif
1941
1942                 public event ItemDragEventHandler ItemDrag {
1943                         add { Events.AddHandler (ItemDragEvent, value); }
1944                         remove { Events.RemoveHandler (ItemDragEvent, value); }
1945                 }
1946
1947                 public event TreeViewEventHandler AfterCheck {
1948                         add { Events.AddHandler (AfterCheckEvent, value); }
1949                         remove { Events.RemoveHandler (AfterCheckEvent, value); }
1950                 }
1951
1952                 public event TreeViewEventHandler AfterCollapse {
1953                         add { Events.AddHandler (AfterCollapseEvent, value); }
1954                         remove { Events.RemoveHandler (AfterCollapseEvent, value); }
1955                 }
1956
1957                 public event TreeViewEventHandler AfterExpand {
1958                         add { Events.AddHandler (AfterExpandEvent, value); }
1959                         remove { Events.RemoveHandler (AfterExpandEvent, value); }
1960                 }
1961
1962                 public event NodeLabelEditEventHandler AfterLabelEdit {
1963                         add { Events.AddHandler (AfterLabelEditEvent, value); }
1964                         remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
1965                 }
1966
1967                 public event TreeViewEventHandler AfterSelect {
1968                         add { Events.AddHandler (AfterSelectEvent, value); }
1969                         remove { Events.RemoveHandler (AfterSelectEvent, value); }
1970                 }
1971
1972                 public event TreeViewCancelEventHandler BeforeCheck {
1973                         add { Events.AddHandler (BeforeCheckEvent, value); }
1974                         remove { Events.RemoveHandler (BeforeCheckEvent, value); }
1975                 }
1976
1977                 public event TreeViewCancelEventHandler BeforeCollapse {
1978                         add { Events.AddHandler (BeforeCollapseEvent, value); }
1979                         remove { Events.RemoveHandler (BeforeCollapseEvent, value); }
1980                 }
1981
1982                 public event TreeViewCancelEventHandler BeforeExpand {
1983                         add { Events.AddHandler (BeforeExpandEvent, value); }
1984                         remove { Events.RemoveHandler (BeforeExpandEvent, value); }
1985                 }
1986
1987                 public event NodeLabelEditEventHandler BeforeLabelEdit {
1988                         add { Events.AddHandler (BeforeLabelEditEvent, value); }
1989                         remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
1990                 }
1991
1992                 public event TreeViewCancelEventHandler BeforeSelect {
1993                         add { Events.AddHandler (BeforeSelectEvent, value); }
1994                         remove { Events.RemoveHandler (BeforeSelectEvent, value); }
1995                 }
1996
1997 #if NET_2_0
1998                 public event DrawTreeNodeEventHandler DrawNode {
1999                         add { Events.AddHandler (DrawNodeEvent, value); }
2000                         remove { Events.RemoveHandler (DrawNodeEvent, value); }
2001                 }
2002
2003                 public event TreeNodeMouseClickEventHandler NodeMouseClick {
2004                         add { Events.AddHandler (NodeMouseClickEvent, value); }
2005                         remove { Events.RemoveHandler (NodeMouseClickEvent, value); }
2006                 }
2007
2008
2009                 public event TreeNodeMouseClickEventHandler NodeMouseDoubleClick {
2010                         add { Events.AddHandler (NodeMouseDoubleClickEvent, value); }
2011                         remove { Events.RemoveHandler (NodeMouseDoubleClickEvent, value); }
2012                 }
2013 #endif
2014
2015                 [Browsable (false)]
2016                 [EditorBrowsable (EditorBrowsableState.Never)]  
2017                 public new event EventHandler BackgroundImageChanged {
2018                         add { base.BackgroundImageChanged += value; }
2019                         remove { base.BackgroundImageChanged -= value; }
2020                 }
2021
2022                 [EditorBrowsable (EditorBrowsableState.Never)]  
2023                 [Browsable (false)]
2024                 public new event PaintEventHandler Paint {
2025                         add { base.Paint += value; }
2026                         remove { base.Paint -= value; }
2027                 }
2028
2029                 [EditorBrowsable (EditorBrowsableState.Never)]  
2030                 [Browsable (false)]
2031                 public new event EventHandler TextChanged {
2032                         add { base.TextChanged += value; }
2033                         remove { base.TextChanged -= value; }
2034                 }
2035                 #endregion      // Events
2036         }
2037 }
2038