importing messaging-2008 branch to trunk.
[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 #if NET_2_0
36         [ComVisible (true)]
37         [Docking (DockingBehavior.Ask)]
38         [ClassInterface (ClassInterfaceType.AutoDispatch)]
39 #endif
40         [DefaultProperty("Nodes")]
41         [DefaultEvent("AfterSelect")]
42         [Designer("System.Windows.Forms.Design.TreeViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
43         public class TreeView : Control {
44                 #region Fields
45                 private string path_separator = "\\";
46                 private int item_height = -1;
47                 private bool sorted;
48                 internal TreeNode root_node;
49                 internal bool nodes_added;
50                 private TreeNodeCollection nodes;
51
52                 private TreeViewAction selection_action;
53                 internal TreeNode selected_node;
54                 private TreeNode pre_selected_node;
55                 private TreeNode focused_node;
56                 internal TreeNode highlighted_node;
57                 private Rectangle mouse_rect;
58                 private bool select_mmove;
59
60                 private ImageList image_list;
61                 private int image_index = -1;
62                 private int selected_image_index = -1;
63
64 #if NET_2_0
65                 private string image_key;
66                 private bool is_hovering;
67                 private TreeNode mouse_click_node;
68                 private bool right_to_left_layout;
69                 private string selected_image_key;
70                 private bool show_node_tool_tips;
71                 private ImageList state_image_list;
72                 private TreeNode tooltip_currently_showing;
73                 private ToolTip tooltip_window;
74 #endif
75                 private bool full_row_select;
76                 private bool hot_tracking;
77                 private int indent = 19;
78
79                 private NodeLabelEditEventArgs edit_args;
80                 private LabelEditTextBox edit_text_box;
81                 internal TreeNode edit_node;
82                 
83                 private bool checkboxes;
84                 private bool label_edit;
85                 private bool scrollable = true;
86                 private bool show_lines = true;
87                 private bool show_root_lines = true;
88                 private bool show_plus_minus = true;
89                 private bool hide_selection = true;
90
91                 private int max_visible_order = -1;
92                 internal VScrollBar vbar;
93                 internal HScrollBar hbar;
94                 private bool vbar_bounds_set;
95                 private bool hbar_bounds_set;
96                 internal int skipped_nodes;
97                 internal int hbar_offset;
98                 
99                 private int update_stack;
100                 private bool update_needed;
101                 
102                 private Pen dash;
103                 private Color line_color;
104                 private StringFormat string_format;
105
106                 private int drag_begin_x = -1;
107                 private int drag_begin_y = -1;
108                 private long handle_count = 1;
109
110                 private TreeViewDrawMode draw_mode;
111
112 #if NET_2_0
113                 IComparer tree_view_node_sorter;
114 #endif
115                 #endregion      // Fields
116
117                 #region Public Constructors     
118                 public TreeView ()
119                 {
120                         vbar = new ImplicitVScrollBar ();
121                         hbar = new ImplicitHScrollBar ();
122
123                         InternalBorderStyle = BorderStyle.Fixed3D;
124                         base.background_color = ThemeEngine.Current.ColorWindow;
125                         base.foreground_color = ThemeEngine.Current.ColorWindowText;
126                         draw_mode = TreeViewDrawMode.Normal;
127
128                         root_node = new TreeNode (this);
129                         root_node.Text = "ROOT NODE";
130                         nodes = new TreeNodeCollection (root_node);
131                         root_node.SetNodes (nodes);
132
133                         MouseDown += new MouseEventHandler (MouseDownHandler);
134                         MouseUp += new MouseEventHandler(MouseUpHandler);
135                         MouseMove += new MouseEventHandler(MouseMoveHandler);
136                         SizeChanged += new EventHandler (SizeChangedHandler);
137                         FontChanged += new EventHandler (FontChangedHandler);
138                         LostFocus += new EventHandler (LostFocusHandler);
139                         GotFocus += new EventHandler (GotFocusHandler);
140                         MouseWheel += new MouseEventHandler(MouseWheelHandler);
141                         VisibleChanged += new EventHandler (VisibleChangedHandler);
142
143                         SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
144 #if NET_2_0
145                                 | ControlStyles.UseTextForAccessibility
146 #endif
147                                 , false);
148
149                         string_format = new StringFormat ();
150                         string_format.LineAlignment = StringAlignment.Center;
151                         string_format.Alignment = StringAlignment.Center;
152
153                         vbar.Visible = false;
154                         hbar.Visible = false;
155                         vbar.ValueChanged += new EventHandler (VScrollBarValueChanged);
156                         hbar.ValueChanged += new EventHandler (HScrollBarValueChanged);
157
158                         SuspendLayout ();
159                         Controls.AddImplicit (vbar);
160                         Controls.AddImplicit (hbar);
161                         ResumeLayout ();
162                 }
163
164                 #endregion      // Public Constructors
165
166                 #region Public Instance Properties
167                 public override Color BackColor {
168                         get { return base.BackColor;}
169                         set {
170                                 base.BackColor = value;
171
172                                 CreateDashPen ();
173                                 Invalidate ();
174                         }
175                 }
176
177
178                 [Browsable(false)]
179                 [EditorBrowsable(EditorBrowsableState.Never)]
180                 public override Image BackgroundImage {
181                         get { return base.BackgroundImage; }
182                         set { base.BackgroundImage = value; }
183                 }
184
185                 [DefaultValue(BorderStyle.Fixed3D)]
186                 [DispId(-504)]
187                 public BorderStyle BorderStyle {
188                         get { return InternalBorderStyle; }
189                         set { InternalBorderStyle  = value; }
190                 }
191
192                 [DefaultValue(false)]
193                 public bool CheckBoxes {
194                         get { return checkboxes; }
195                         set {
196                                 if (value == checkboxes)
197                                         return;
198                                 checkboxes = value;
199
200                                 // Match a "bug" in the MS implementation where disabling checkboxes
201                                 // collapses the entire tree, but enabling them does not affect the
202                                 // state of the tree.
203                                 if (!checkboxes)
204                                         root_node.CollapseAllUncheck ();
205
206                                 Invalidate ();
207                         }
208                 }
209
210                 public override Color ForeColor {
211                         get { return base.ForeColor; }
212                         set { base.ForeColor = value; }
213                 }
214                 [DefaultValue(false)]
215                 public bool FullRowSelect {
216                         get { return full_row_select; }
217                         set {
218                                 if (value == full_row_select)
219                                         return;
220                                 full_row_select = value;
221                                 Invalidate ();
222                         }
223                 }
224                 [DefaultValue(true)]
225                 public bool HideSelection {
226                         get { return hide_selection; }
227                         set {
228                                 if (hide_selection == value)
229                                         return;
230                                 hide_selection = value;
231                                 Invalidate ();
232                         }
233                 }
234
235                 [DefaultValue(false)]
236                 public bool HotTracking {
237                         get { return hot_tracking; }
238                         set { hot_tracking = value; }
239                 }
240
241 #if NET_2_0
242                 [DefaultValue (-1)]
243                 [RelatedImageList ("ImageList")]
244                 [RefreshProperties (RefreshProperties.Repaint)]
245                 [TypeConverter (typeof (NoneExcludedImageIndexConverter))]
246 #else
247                 [DefaultValue (0)]
248                 [TypeConverter (typeof (TreeViewImageIndexConverter))]
249 #endif
250                 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
251                 [Localizable(true)]
252                 public int ImageIndex {
253                         get { return image_index; }
254                         set {
255                                 if (value < -1) {
256                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
257                                                 "'value' must be greater than or equal to 0.");
258                                 }
259                                 if (image_index == value)
260                                         return;
261                                 image_index = value;
262                                 Invalidate ();
263                         }
264                 }
265
266 #if NET_2_0
267                 [RefreshProperties (RefreshProperties.Repaint)]
268 #endif
269                 [DefaultValue(null)]
270                 public ImageList ImageList {
271                         get { return image_list; }
272                         set {
273                                 image_list = value;
274                                 Invalidate ();
275                         }
276                 }
277
278                 [Localizable(true)]
279                 public int Indent {
280                         get { return indent; }
281                         set {
282                                 if (indent == value)
283                                         return;
284                                 if (value > 32000) {
285                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
286                                                 "'Indent' must be less than or equal to 32000");
287                                 }       
288                                 if (value < 0) {
289                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
290                                                 "'Indent' must be greater than or equal to 0.");
291                                 }
292                                 indent = value;
293                                 Invalidate ();
294                         }
295                 }
296
297 #if !NET_2_0
298                 [Localizable(true)]
299 #endif
300                 public int ItemHeight {
301                         get {
302                                 if (item_height == -1)
303                                         return FontHeight + 3;
304                                 return item_height;
305                         }
306                         set {
307                                 if (value == item_height)
308                                         return;
309                                 item_height = value;
310                                 Invalidate ();
311                         }
312                 }
313
314                 internal int ActualItemHeight {
315                         get {
316                                 int res = ItemHeight;
317                                 if (ImageList != null && ImageList.ImageSize.Height > res)
318                                         res = ImageList.ImageSize.Height;
319                                 return res;
320                         }
321                 }
322
323                 [DefaultValue(false)]
324                 public bool LabelEdit {
325                         get { return label_edit; }
326                         set { label_edit = value; }
327                 }
328
329                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
330                 [MergableProperty(false)]
331                 [Localizable(true)]
332                 public TreeNodeCollection Nodes {
333                         get { return nodes; }
334                 }
335
336 #if NET_2_0
337                 [Browsable (false)]
338                 [EditorBrowsable (EditorBrowsableState.Never)]
339                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
340                 public new Padding Padding {
341                         get { return base.Padding; }
342                         set { base.Padding = value; }
343                 }
344 #endif
345
346                 [DefaultValue("\\")]
347                 public string PathSeparator {
348                         get { return path_separator; }
349                         set { path_separator = value; }
350                 }
351
352 #if NET_2_0
353                 [Localizable (true)]
354                 [DefaultValue (false)]
355                 public virtual bool RightToLeftLayout {
356                         get { return right_to_left_layout; }
357                         set { 
358                                 if (right_to_left_layout != value) {
359                                         right_to_left_layout = value;
360                                         OnRightToLeftLayoutChanged (EventArgs.Empty);   
361                                 }
362                         }
363                 }
364 #endif
365
366                 [DefaultValue(true)]
367                 public bool Scrollable {
368                         get { return scrollable; }
369                         set {
370                                 if (scrollable == value)
371                                         return;
372                                 scrollable = value;
373                                 UpdateScrollBars (false);
374                         }
375                 }
376
377 #if NET_2_0
378                 [DefaultValue (-1)]
379                 [RelatedImageList ("ImageList")]
380                 [TypeConverter (typeof (NoneExcludedImageIndexConverter))]
381 #else
382                 [DefaultValue (0)]
383                 [TypeConverter (typeof (TreeViewImageIndexConverter))]
384 #endif
385                 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
386                 [Localizable(true)]
387                 public int SelectedImageIndex {
388                         get { return selected_image_index; }
389                         set {
390                                 if (value < -1) {
391                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
392                                                 "'value' must be greater than or equal to 0.");
393                                 }
394                                 UpdateNode (SelectedNode);
395                         }
396                 }
397
398                 [Browsable(false)]
399                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
400                 public TreeNode SelectedNode {
401                         get {
402                                 if (!IsHandleCreated)
403                                         return pre_selected_node;
404                                 return selected_node;
405                         }
406                         set {
407                                 if (!IsHandleCreated) {
408                                         pre_selected_node = value;
409                                         return;
410                                 }
411
412                                 if (selected_node == value) {
413                                         selection_action = TreeViewAction.Unknown;
414                                         return;
415                                 }
416
417                                 if (value != null) {
418                                         TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (value, false, selection_action);
419                                         OnBeforeSelect (e);
420
421                                         if (e.Cancel)
422                                                 return;
423                                 }
424
425                                 Rectangle invalid = Rectangle.Empty;
426
427                                 if (selected_node != null) {
428                                         invalid = Bloat (selected_node.Bounds);
429                                 }
430                                 if (focused_node != null) {
431                                         invalid = Rectangle.Union (invalid,
432                                                         Bloat (focused_node.Bounds));
433                                 }
434
435                                 if (value != null)
436                                         invalid = Rectangle.Union (invalid, Bloat (value.Bounds));
437
438                                 highlighted_node = value;
439                                 selected_node = value;
440                                 focused_node = value;
441
442                                 if (full_row_select || draw_mode != TreeViewDrawMode.Normal) {
443                                         invalid.X = 0;
444                                         invalid.Width = ViewportRectangle.Width;
445                                 }
446
447                                 if (invalid != Rectangle.Empty)
448                                         Invalidate (invalid);
449
450                                 // We ensure its visible after we update because
451                                 // scrolling is used for insure visible
452                                 if (selected_node != null)
453                                         selected_node.EnsureVisible ();
454
455                                 if (value != null) {
456                                         OnAfterSelect (new TreeViewEventArgs (value, TreeViewAction.Unknown));
457                                 }
458                                 selection_action = TreeViewAction.Unknown;
459                         }
460                 }
461
462                 private Rectangle Bloat (Rectangle rect)
463                 {
464                         rect.Y--;
465                         rect.X--;
466                         rect.Height += 2;
467                         rect.Width += 2;
468                         return rect;
469                 }
470
471                 [DefaultValue(true)]
472                 public bool ShowLines {
473                         get { return show_lines; }
474                         set {
475                                 if (show_lines == value)
476                                         return;
477                                 show_lines = value;
478                                 Invalidate ();
479                         }
480                 }
481
482 #if NET_2_0
483                 [DefaultValue (false)]
484                 public bool ShowNodeToolTips {
485                         get { return show_node_tool_tips; }
486                         set { show_node_tool_tips = value; }
487                 }
488 #endif
489
490                 [DefaultValue(true)]
491                 public bool ShowPlusMinus {
492                         get { return show_plus_minus; }
493                         set {
494                                 if (show_plus_minus == value)
495                                         return;
496                                 show_plus_minus = value;
497                                 Invalidate ();
498                         }
499                 }
500
501                 [DefaultValue(true)]
502                 public bool ShowRootLines {
503                         get { return show_root_lines; }
504                         set {
505                                 if (show_root_lines == value)
506                                         return;
507                                 show_root_lines = value;
508                                 Invalidate ();
509                         }
510                 }
511
512 #if NET_2_0
513                 [Browsable (false)]
514                 [EditorBrowsable (EditorBrowsableState.Never)]
515 #endif
516                 [DefaultValue(false)]
517                 public bool Sorted {
518                         get { return sorted; }
519                         set {
520 #if NET_2_0
521                                 if (sorted == value)
522                                         return;
523                                 sorted = value;
524                                 //LAMESPEC: The documentation says that setting this to true should sort alphabetically if TreeViewNodeSorter is set.
525                                 // There seems to be a bug in the Microsoft implementation.
526                                 if (sorted && tree_view_node_sorter == null) {
527                                         Sort (null);
528                                 }
529 #else
530                                 if (sorted != value)
531                                         sorted = value;
532                                 if (sorted) {
533                                         Sort (null);
534                                 }
535 #endif
536                         }
537                 }
538
539 #if NET_2_0
540                 [DefaultValue (null)]
541                 public ImageList StateImageList {
542                         get { return state_image_list; }
543                         set { 
544                                 state_image_list = value;
545                                 Invalidate ();
546                         }
547                 }
548 #endif
549
550                 [Browsable(false)]
551                 [EditorBrowsable(EditorBrowsableState.Never)]
552                 [Bindable(false)]
553                 public override string Text {
554                         get { return base.Text; }
555                         set { base.Text = value; }
556                 }
557
558                 [Browsable(false)]
559                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
560                 public TreeNode TopNode {
561                         get {
562                                 if (root_node.FirstNode == null)
563                                         return null;
564                                 OpenTreeNodeEnumerator one = new OpenTreeNodeEnumerator (root_node.FirstNode);
565                                 one.MoveNext ();
566                                 for (int i = 0; i < skipped_nodes; i++)
567                                         one.MoveNext ();
568                                 return one.CurrentNode;
569                         }
570 #if NET_2_0
571                         set {
572                                 SetTop (value);
573                         }
574 #endif
575                 }
576
577 #if NET_2_0
578                 [Browsable (false)]
579                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
580                 public IComparer TreeViewNodeSorter {
581                         get {
582                                 return tree_view_node_sorter;
583                         }
584                         set {
585                                 tree_view_node_sorter = value;
586                                 if (tree_view_node_sorter != null) {
587                                         Sort();
588                                         //LAMESPEC: The documentation says that setting this should set Sorted to false.
589                                         // There seems to be a bug in the Microsoft implementation.
590                                         sorted = true;
591                                 }
592                         }
593                 }
594 #endif
595
596                 [Browsable(false)]
597                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
598                 public int VisibleCount {
599                         get {
600                                 return ViewportRectangle.Height / ActualItemHeight;
601                         }
602                 }
603
604 #if NET_2_0
605                 /// According to MSDN this property has no effect on the treeview
606                 [EditorBrowsable (EditorBrowsableState.Never)]
607                 protected override bool DoubleBuffered {
608                         get { return base.DoubleBuffered; }
609                         set { base.DoubleBuffered = value; }
610                 }
611 #endif
612
613 #if NET_2_0
614                 [DefaultValue ("Color [Black]")]
615                 public
616 #else
617                 private
618 #endif
619                 Color LineColor {
620                         get {
621                                 if (line_color == Color.Empty) {
622                                         Color res = ControlPaint.Dark (BackColor);
623                                         if (res == BackColor)
624                                                 res = ControlPaint.Light (BackColor);
625                                         return res;
626                                 }
627                                 return line_color;
628                         }
629                         set {
630                                 line_color = value;
631                                 if (show_lines) {
632                                         CreateDashPen ();
633                                         Invalidate ();
634                                 }
635                         }
636                 }
637 #if NET_2_0
638                 [Localizable (true)]
639                 [DefaultValue ("")]
640                 [RelatedImageList ("ImageList")]
641                 [RefreshProperties (RefreshProperties.Repaint)]
642                 [TypeConverter (typeof (ImageKeyConverter))]
643                 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
644                 public string ImageKey {
645                         get { return image_key; }
646                         set {
647                                 if (image_key == value)
648                                         return;
649                                 image_index = -1;
650                                 image_key = value;
651                                 Invalidate ();
652                         }
653                 }
654
655                 [Localizable (true)]
656                 [DefaultValue ("")]
657                 [RelatedImageList ("ImageList")]
658                 [RefreshProperties (RefreshProperties.Repaint)]
659                 [TypeConverter (typeof (ImageKeyConverter))]
660                 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
661                 public string SelectedImageKey {
662                         get { return selected_image_key; }
663                         set {
664                                 if (selected_image_key == value)
665                                         return;
666                                 selected_image_index = -1;
667                                 selected_image_key = value;
668                                 UpdateNode (SelectedNode);
669                         }
670                 }
671 #endif
672
673 #if NET_2_0
674                 [Browsable (false)]
675                 [EditorBrowsable (EditorBrowsableState.Never)]
676                 public override ImageLayout BackgroundImageLayout {
677                         get { return base.BackgroundImageLayout; }
678                         set { base.BackgroundImageLayout = value; }
679                 }
680 #endif
681
682 #if NET_2_0
683                 [DefaultValue (TreeViewDrawMode.Normal)]
684                 public TreeViewDrawMode DrawMode {
685                         get { return draw_mode; }
686                         set { draw_mode = value; }
687                 }
688 #endif
689                 #endregion      // Public Instance Properties
690
691                 #region Protected Instance Properties
692                 protected override CreateParams CreateParams {
693                         get {
694                                 CreateParams cp = base.CreateParams;
695                                 return cp;
696                         }
697                 }
698
699                 protected override Size DefaultSize {
700                         get { return new Size (121, 97); }
701                 }
702
703                 #endregion      // Protected Instance Properties
704
705                 #region Public Instance Methods
706                 public void BeginUpdate ()
707                 {
708                         update_stack++;
709                 }
710
711                 public void EndUpdate ()
712                 {
713                         if (update_stack > 1) {
714                                 update_stack--;
715                         } else {
716                                 update_stack = 0;
717                                 if (update_needed) {
718                                         RecalculateVisibleOrder (root_node);
719                                         UpdateScrollBars (false);
720                                         //      if (SelectedNode != null)
721                                         //              SelectedNode.EnsureVisible ();
722                                         Invalidate (ViewportRectangle);
723                                         update_needed = false;
724                                 }
725                         }
726                 }
727
728 #if NET_2_0
729                 public  void Sort ()
730                 {
731                         Sort (Nodes.Count >= 2 ? tree_view_node_sorter : null);
732                 }
733 #endif
734
735                 void Sort (IComparer sorter) 
736                 {
737                         sorted = true;
738                         Nodes.Sort (sorter);
739                         RecalculateVisibleOrder (root_node);
740                         UpdateScrollBars (false);
741                         Invalidate ();
742                 }
743
744                 public void ExpandAll ()
745                 {
746                         BeginUpdate ();
747                         root_node.ExpandAll ();
748
749                         EndUpdate ();
750
751                         ///
752                         /// Everything below this is basically an emulation of a strange bug on MS
753                         /// where they don't always scroll to the last node on ExpandAll
754                         ///
755 #if NET_2_0
756                         if (!IsHandleCreated)
757                                 return;
758 #endif
759                         
760                         bool found = false;
761                         foreach (TreeNode child in Nodes) {
762                                 if (child.Nodes.Count > 0)
763                                         found = true;
764                         }
765                         
766                         if (!found)
767                                 return;
768
769                         if (IsHandleCreated && vbar.VisibleInternal) {
770                                 vbar.Value = vbar.Maximum - VisibleCount + 1;
771                         } else {
772                                 RecalculateVisibleOrder (root_node);
773                                 UpdateScrollBars (true);
774                                 
775                                 // Only move the top node if we now have a scrollbar
776                                 if (vbar.VisibleInternal) {
777                                         SetTop (Nodes [Nodes.Count - 1]);
778                                         SelectedNode = Nodes [Nodes.Count - 1];
779                                 }
780                         }
781                 }
782
783                 
784                 public void CollapseAll ()
785                 {
786                         TreeNode walk = TopNode;
787                         
788                         if (walk == null)
789                                 return;
790                                 
791                         while (walk.parent != root_node)
792                                 walk = walk.parent;
793
794                         BeginUpdate ();
795                         root_node.CollapseAll ();
796                         EndUpdate ();
797
798                         SetTop (walk);
799                 }
800
801                 public TreeNode GetNodeAt (Point pt) {
802                         return GetNodeAt (pt.Y);
803                 }
804
805                 public TreeNode GetNodeAt (int x, int y)
806                 {
807                         return GetNodeAt (y);
808                 }
809
810                 private TreeNode GetNodeAtUseX (int x, int y) {
811                         TreeNode node = GetNodeAt (y);
812                         if (node == null || !(IsTextArea (node, x) || full_row_select))
813                                 return null;
814                         return node;
815                                         
816                 }
817
818                 public int GetNodeCount (bool includeSubTrees) {
819                         return root_node.GetNodeCount (includeSubTrees);
820                 }
821
822 #if NET_2_0
823                 public TreeViewHitTestInfo HitTest (Point pt)
824                 {
825                         return HitTest (pt.X, pt.Y);
826                 }
827                 
828                 public TreeViewHitTestInfo HitTest (int x, int y)
829                 {
830                         TreeNode n = GetNodeAt (y);
831                         
832                         if (n == null)
833                                 return new TreeViewHitTestInfo (null, TreeViewHitTestLocations.None);
834                                 
835                         if (IsTextArea (n, x))
836                                 return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.Label);
837                         else if (IsPlusMinusArea (n, x))
838                                 return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.PlusMinus);
839                         else if ((checkboxes || n.StateImage != null) && IsCheckboxArea (n, x))
840                                 return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.StateImage);
841                         else if (x > n.Bounds.Right)
842                                 return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.RightOfLabel);
843                         else if (IsImage (n, x))
844                                 return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.Image);
845                         else
846                                 return new TreeViewHitTestInfo (null, TreeViewHitTestLocations.Indent);
847                 }
848 #endif
849
850                 public override string ToString () {
851                         int count = Nodes.Count;
852                         if (count <= 0)
853                                 return String.Concat (base.ToString (), ", Nodes.Count: 0");
854                         return String.Concat (base.ToString (), ", Nodes.Count: ", count, ", Nodes[0]: ", Nodes [0]);
855                                                 
856                 }
857
858                 #endregion      // Public Instance Methods
859
860                 #region Protected Instance Methods
861                 protected override void CreateHandle () {
862                         base.CreateHandle ();
863                         RecalculateVisibleOrder (root_node);
864                         UpdateScrollBars (false);
865
866                         if (pre_selected_node != null)
867                                 SelectedNode = pre_selected_node;
868                 }
869
870                 protected override void Dispose (bool disposing) {
871                         if (disposing)
872                                 image_list = null;
873
874                         base.Dispose (disposing);
875                 }
876
877                 protected OwnerDrawPropertyBag GetItemRenderStyles (TreeNode node, int state) {
878                         return node.prop_bag;
879                 }
880
881                 protected override bool IsInputKey (Keys keyData)
882                 {
883                         if (IsHandleCreated && (keyData & Keys.Alt) == 0) {
884                                 switch (keyData & Keys.KeyCode) {
885                                 case Keys.Left:
886                                 case Keys.Up:
887                                 case Keys.Right:
888                                 case Keys.Down:
889                                         return true;
890                                 case Keys.Enter:
891                                 case Keys.Escape:
892                                 case Keys.Prior:
893                                 case Keys.Next:
894                                 case Keys.End:
895                                 case Keys.Home:
896                                         if (edit_node != null)
897                                                 return true;
898                                                 
899                                         break;
900                                 }
901                         }
902                         return base.IsInputKey (keyData);
903                 }
904
905                 protected override void OnKeyDown (KeyEventArgs e)
906                 {
907                         OpenTreeNodeEnumerator ne;
908
909                         switch (e.KeyData & Keys.KeyCode) {
910                         case Keys.Add:
911                                 if (selected_node != null && selected_node.IsExpanded)
912                                         selected_node.Expand ();
913                                 break;
914                         case Keys.Subtract:
915                                 if (selected_node != null && selected_node.IsExpanded)
916                                         selected_node.Collapse ();
917                                 break;
918                         case Keys.Left:
919                                 if (selected_node != null) {
920                                         if (selected_node.IsExpanded && selected_node.Nodes.Count > 0)
921                                                 selected_node.Collapse ();
922                                         else {
923                                                 TreeNode parent = selected_node.Parent;
924                                                 if (parent != null) {
925                                                         selection_action = TreeViewAction.ByKeyboard;
926                                                         SelectedNode = parent;
927                                                 }
928                                         }
929                                 }
930                                 break;
931                         case Keys.Right:
932                                 if (selected_node != null) {
933                                         if (!selected_node.IsExpanded)
934                                                 selected_node.Expand ();
935                                         else {
936                                                 TreeNode child = selected_node.FirstNode;
937                                                 if (child != null)
938                                                         SelectedNode = child;
939                                         }
940                                 }
941                                 break;
942                         case Keys.Up:
943                                 if (selected_node != null) {
944                                         ne = new OpenTreeNodeEnumerator (selected_node);
945                                         if (ne.MovePrevious () && ne.MovePrevious ()) {
946                                                 selection_action = TreeViewAction.ByKeyboard;
947                                                 SelectedNode = ne.CurrentNode;
948                                         }
949                                 }
950                                 break;
951                         case Keys.Down:
952                                 if (selected_node != null) {
953                                         ne = new OpenTreeNodeEnumerator (selected_node);
954                                         if (ne.MoveNext () && ne.MoveNext ()) {
955                                                 selection_action = TreeViewAction.ByKeyboard;
956                                                 SelectedNode = ne.CurrentNode;
957                                         }
958                                 }
959                                 break;
960                         case Keys.Home:
961                                 if (root_node.Nodes.Count > 0) {
962                                         ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]);
963                                         if (ne.MoveNext ()) {
964                                                 selection_action = TreeViewAction.ByKeyboard;
965                                                 SelectedNode = ne.CurrentNode;
966                                         }
967                                 }
968                                 break;
969                         case Keys.End:
970                                 if (root_node.Nodes.Count > 0) {
971                                         ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]);
972                                         while (ne.MoveNext ())
973                                         { }
974                                         selection_action = TreeViewAction.ByKeyboard;
975                                         SelectedNode = ne.CurrentNode;
976                                 }
977                                 break;
978                         case Keys.PageDown:
979                                 if (selected_node != null) {
980                                         ne = new OpenTreeNodeEnumerator (selected_node);
981                                         int move = VisibleCount;
982                                         for (int i = 0; i < move && ne.MoveNext (); i++) {
983                                                 
984                                         }
985                                         selection_action = TreeViewAction.ByKeyboard;
986                                         SelectedNode = ne.CurrentNode;
987                                 }
988                                 break;
989                         case Keys.PageUp:
990                                 if (selected_node != null) {
991                                         ne = new OpenTreeNodeEnumerator (selected_node);
992                                         int move = VisibleCount;
993                                         for (int i = 0; i < move && ne.MovePrevious (); i++)
994                                         { }
995                                         selection_action = TreeViewAction.ByKeyboard;
996                                         SelectedNode = ne.CurrentNode;
997                                 }
998                                 break;
999                         case Keys.Multiply:
1000                                 if (selected_node != null)
1001                                         selected_node.ExpandAll ();
1002                                 break;
1003                         }
1004                         base.OnKeyDown (e);
1005
1006                         if (!e.Handled && checkboxes &&
1007                              selected_node != null &&
1008                             (e.KeyData & Keys.KeyCode) == Keys.Space) {
1009                                 selected_node.check_reason = TreeViewAction.ByKeyboard;
1010                                 selected_node.Checked = !selected_node.Checked;         
1011                                 e.Handled = true;
1012                         }
1013                 }
1014
1015                 protected override void OnKeyPress (KeyPressEventArgs e)
1016                 {
1017                         base.OnKeyPress (e);
1018                         if (e.KeyChar == ' ')
1019                                 e.Handled = true;
1020                 }
1021
1022                 protected override void OnKeyUp (KeyEventArgs e)
1023                 {
1024                         base.OnKeyUp (e);
1025                         if ((e.KeyData & Keys.KeyCode) == Keys.Space)
1026                                 e.Handled = true;
1027                 }
1028
1029 #if NET_2_0
1030                 protected override void OnMouseHover (EventArgs e)
1031                 {
1032                         base.OnMouseHover (e);
1033                         
1034                         is_hovering = true;
1035
1036                         TreeNode tn = GetNodeAt (PointToClient (MousePosition));
1037
1038                         if (tn != null)
1039                                 MouseEnteredItem (tn);
1040                 }
1041
1042                 protected override void OnMouseLeave (EventArgs e)
1043                 {
1044                         base.OnMouseLeave (e);
1045                         
1046                         is_hovering = false;
1047                         
1048                         if (tooltip_currently_showing != null)
1049                                 MouseLeftItem (tooltip_currently_showing);
1050                 }
1051                 
1052                 protected virtual void OnNodeMouseClick (TreeNodeMouseClickEventArgs e)
1053                 {
1054                         TreeNodeMouseClickEventHandler eh = (TreeNodeMouseClickEventHandler)(Events[NodeMouseClickEvent]);
1055                         if (eh != null)
1056                                 eh (this, e);
1057                 }
1058
1059                 protected virtual void OnNodeMouseDoubleClick (TreeNodeMouseClickEventArgs e)
1060                 {
1061                         TreeNodeMouseClickEventHandler eh = (TreeNodeMouseClickEventHandler)(Events[NodeMouseDoubleClickEvent]);
1062                         if (eh != null)
1063                                 eh (this, e);
1064                 }
1065                 
1066                 protected virtual void OnNodeMouseHover (TreeNodeMouseHoverEventArgs e)
1067                 {
1068                         TreeNodeMouseHoverEventHandler eh = (TreeNodeMouseHoverEventHandler)(Events[NodeMouseHoverEvent]);
1069                         if (eh != null)
1070                                 eh (this, e);
1071                 }
1072 #endif
1073
1074                 protected virtual void OnItemDrag (ItemDragEventArgs e)
1075                 {
1076                         ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
1077                         if (eh != null)
1078                                 eh (this, e);
1079                 }
1080
1081 #if NET_2_0
1082                 protected virtual void OnDrawNode(DrawTreeNodeEventArgs e) {
1083                         DrawTreeNodeEventHandler eh = (DrawTreeNodeEventHandler)(Events[DrawNodeEvent]);
1084                         if (eh != null)
1085                                 eh(this, e);
1086                 }
1087                 
1088                 [EditorBrowsable (EditorBrowsableState.Advanced)]
1089                 protected virtual void OnRightToLeftLayoutChanged (EventArgs e) {
1090                         EventHandler eh = (EventHandler)(Events[RightToLeftLayoutChangedEvent]);
1091                         if (eh != null)
1092                                 eh (this, e);
1093                 }
1094 #endif
1095
1096                 protected internal virtual void OnAfterCheck (TreeViewEventArgs e) {
1097                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterCheckEvent]);
1098                         if (eh != null)
1099                                 eh (this, e);
1100                 }
1101
1102                 protected internal virtual void OnAfterCollapse (TreeViewEventArgs e) {
1103                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterCollapseEvent]);
1104                         if (eh != null)
1105                                 eh (this, e);
1106                 }
1107
1108                 protected internal virtual void OnAfterExpand (TreeViewEventArgs e) {
1109                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterExpandEvent]);
1110                         if (eh != null)
1111                                 eh (this, e);
1112                 }
1113
1114                 protected virtual void OnAfterLabelEdit (NodeLabelEditEventArgs e) {
1115                         NodeLabelEditEventHandler eh = (NodeLabelEditEventHandler)(Events [AfterLabelEditEvent]);
1116                         if (eh != null)
1117                                 eh (this, e);
1118                 }
1119
1120                 protected virtual void OnAfterSelect (TreeViewEventArgs e) {
1121                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterSelectEvent]);
1122                         if (eh != null)
1123                                 eh (this, e);
1124                 }
1125
1126                 protected internal virtual void OnBeforeCheck (TreeViewCancelEventArgs e) {
1127                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeCheckEvent]);
1128                         if (eh != null)
1129                                 eh (this, e);
1130                 }
1131
1132                 protected internal virtual void OnBeforeCollapse (TreeViewCancelEventArgs e) {
1133                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeCollapseEvent]);
1134                         if (eh != null)
1135                                 eh (this, e);
1136                 }
1137
1138                 protected internal virtual void OnBeforeExpand (TreeViewCancelEventArgs e) {
1139                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeExpandEvent]);
1140                         if (eh != null)
1141                                 eh (this, e);
1142                 }
1143
1144                 protected virtual void OnBeforeLabelEdit (NodeLabelEditEventArgs e) {
1145                         NodeLabelEditEventHandler eh = (NodeLabelEditEventHandler)(Events [BeforeLabelEditEvent]);
1146                         if (eh != null)
1147                                 eh (this, e);
1148                 }
1149
1150                 protected virtual void OnBeforeSelect (TreeViewCancelEventArgs e) {
1151                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeSelectEvent]);
1152                         if (eh != null)
1153                                 eh (this, e);
1154                 }
1155
1156                 protected override void OnHandleCreated (EventArgs e) {
1157                         base.OnHandleCreated (e);
1158                 }
1159
1160                 protected override void OnHandleDestroyed (EventArgs e) {
1161                         base.OnHandleDestroyed (e);
1162                 }
1163
1164                 protected override void WndProc(ref Message m) {
1165                         switch ((Msg) m.Msg) {
1166
1167                         case Msg.WM_LBUTTONDBLCLK:
1168                                 int val = m.LParam.ToInt32();
1169                                 DoubleClickHandler (null, new
1170                                                 MouseEventArgs (MouseButtons.Left,
1171                                                                 2, val & 0xffff,
1172                                                                 (val>>16) & 0xffff, 0));
1173                                         break;
1174 #if NET_2_0
1175                                 case Msg.WM_CONTEXTMENU:
1176                                         if (WmContextMenu (ref m))
1177                                                 return;
1178                                                 
1179                                         break;
1180 #endif
1181                         }
1182                         base.WndProc (ref m);
1183                 }
1184
1185                 #endregion      // Protected Instance Methods
1186
1187                 #region Internal & Private Methods and Properties
1188                 internal override bool ScaleChildrenInternal {
1189                         get { return false; }
1190                 }
1191
1192                 internal IntPtr CreateNodeHandle ()
1193                 {
1194                         return (IntPtr) handle_count++;
1195                 }
1196
1197                 // According to MSDN docs, for these to be raised, 
1198                 // the click must occur over a TreeNode
1199                 internal override void HandleClick (int clicks, MouseEventArgs me)
1200                 {
1201                         if (GetNodeAt (me.Location) != null) {
1202                                 if ((clicks > 1) && GetStyle (ControlStyles.StandardDoubleClick)) {
1203 #if !NET_2_0
1204                                         OnDoubleClick(EventArgs.Empty);
1205                                 } else {
1206                                         OnClick(EventArgs.Empty);
1207 #else
1208                                         OnDoubleClick (me);
1209                                         OnMouseDoubleClick (me);
1210                                 } else {
1211                                         OnClick (me);
1212                                         OnMouseClick (me);
1213 #endif
1214                                 }
1215                         }
1216                 }
1217                 
1218                 internal override bool IsInputCharInternal (char charCode)
1219                 {
1220                         return true;
1221                 }
1222
1223                 internal TreeNode NodeFromHandle (IntPtr handle)
1224                 {
1225                         // This method is called rarely, so instead of maintaining a table
1226                         // we just walk the tree nodes to find the matching handle
1227                         return NodeFromHandleRecursive (root_node,  handle);
1228                 }
1229
1230                 private TreeNode NodeFromHandleRecursive (TreeNode node, IntPtr handle)
1231                 {
1232                         if (node.handle == handle)
1233                                 return node;
1234                         foreach (TreeNode child in node.Nodes) {
1235                                 TreeNode match = NodeFromHandleRecursive (child, handle);
1236                                 if (match != null)
1237                                         return match;
1238                         }
1239                         return null;
1240                 }
1241
1242                 internal Rectangle ViewportRectangle {
1243                         get {
1244                                 Rectangle res = ClientRectangle;
1245
1246                                 if (vbar != null && vbar.Visible)
1247                                         res.Width -= vbar.Width;
1248                                 if (hbar != null && hbar.Visible)
1249                                         res.Height -= hbar.Height;
1250                                 return res;
1251                         }
1252                 }
1253
1254                 private TreeNode GetNodeAt (int y)
1255                 {
1256                         if (nodes.Count <= 0)
1257                                 return null;
1258
1259                         OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (TopNode);
1260                         int move = y / ActualItemHeight;
1261                         for (int i = -1; i < move; i++) {
1262                                 if (!o.MoveNext ())
1263                                         return null;
1264                         }
1265
1266                         return o.CurrentNode;
1267                 }
1268
1269                 private bool IsTextArea (TreeNode node, int x)
1270                 {
1271                         return node != null && node.Bounds.Left <= x && node.Bounds.Right >= x;
1272                 }
1273
1274                 private bool IsSelectableArea (TreeNode node, int x)
1275                 {
1276                         if (node == null)
1277                                 return false;
1278                         int l = node.Bounds.Left;
1279                         if (ImageList != null)
1280                                 l -= ImageList.ImageSize.Width;
1281                         return l <= x && node.Bounds.Right >= x;
1282                                 
1283                 }
1284
1285                 private bool IsPlusMinusArea (TreeNode node, int x)
1286                 {
1287                         if (node.Nodes.Count == 0 || (node.parent == root_node && !show_root_lines))
1288                                 return false;
1289
1290                         int l = node.Bounds.Left + 5;
1291
1292                         if (show_root_lines || node.Parent != null)
1293                                 l -= indent;
1294                         if (ImageList != null)
1295                                 l -= ImageList.ImageSize.Width + 3;
1296                         if (checkboxes)
1297                                 l -= 19;
1298 #if NET_2_0
1299                         // StateImage is basically a custom checkbox
1300                         else if (node.StateImage != null)
1301                                 l -= 19;
1302 #endif
1303                         return (x > l && x < l + 8);
1304                 }
1305
1306                 private bool IsCheckboxArea (TreeNode node, int x)
1307                 {
1308                         int l = CheckBoxLeft (node);
1309                         return (x > l && x < l + 10);
1310                 }
1311
1312 #if NET_2_0
1313                 private bool IsImage (TreeNode node, int x)
1314                 {
1315                         if (ImageList == null)
1316                                 return false;
1317                                 
1318                         int l = node.Bounds.Left;
1319
1320                         l -= ImageList.ImageSize.Width + 5;
1321                         
1322                         if (x >= l && x <= (l + ImageList.ImageSize.Width + 5))
1323                                 return true;
1324                                 
1325                         return false;
1326                 }
1327 #endif
1328                 
1329                 private int CheckBoxLeft (TreeNode node)
1330                 {
1331                         int l = node.Bounds.Left + 5;
1332
1333                         if (show_root_lines || node.Parent != null)
1334                                 l -= indent;
1335                                 
1336                         if (!show_root_lines && node.Parent == null)
1337                                 l -= indent;
1338                                 
1339                         if (ImageList != null)
1340                                 l -= ImageList.ImageSize.Width + 3;
1341
1342                         return l;
1343                 }
1344
1345                 internal void RecalculateVisibleOrder (TreeNode start)
1346                 {
1347                         if (update_stack > 0)
1348                                 return;
1349
1350                         int order;
1351                         if (start == null) {
1352                                 start = root_node;
1353                                 order = 0;
1354                         } else
1355                                 order = start.visible_order;
1356
1357                         
1358                         
1359                         OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (start);
1360                         while (walk.MoveNext ()) {
1361                                 walk.CurrentNode.visible_order = order;
1362                                 order++;
1363                         }
1364
1365                         max_visible_order = order;
1366                 }
1367
1368                 internal void SetTop (TreeNode node)
1369                 {
1370                         int order = 0;
1371                         if (node != null)
1372                                 order = Math.Max (0, node.visible_order - 1);
1373
1374                         if (!vbar.is_visible) {
1375                                 skipped_nodes = order;
1376                                 return;
1377                         }
1378
1379                         vbar.Value = Math.Min (order, vbar.Maximum - VisibleCount + 1);
1380                 }
1381
1382                 internal void SetBottom (TreeNode node)
1383                 {
1384                         if (!vbar.is_visible)
1385                                 return;
1386
1387                         OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (node);
1388
1389                         int bottom = ViewportRectangle.Bottom;
1390                         int offset = 0;
1391                         while (walk.MovePrevious ()) {
1392                                 if (walk.CurrentNode.Bounds.Bottom <= bottom)
1393                                         break;
1394                                 offset++;
1395                         }
1396
1397                         int nv = vbar.Value + offset;
1398                         if (vbar.Value + offset < vbar.Maximum) {
1399                                 vbar.Value = nv;
1400                         } else {
1401 #if DEBUG
1402                                 Console.Error.WriteLine ("setting bottom to value greater then maximum ({0}, {1})",
1403                                                 nv, vbar.Maximum);
1404 #endif
1405                         }
1406                                 
1407                 }
1408
1409                 internal void UpdateBelow (TreeNode node)
1410                 {
1411                         if (update_stack > 0) {
1412                                 update_needed = true;
1413                                 return;
1414                         }
1415
1416                         if (node == root_node) {
1417                                 Invalidate (ViewportRectangle);
1418                                 return;
1419                         }
1420                                 
1421                         // We need to update the current node so the plus/minus block gets update too
1422                         int top = Math.Max (node.Bounds.Top - 1, 0);
1423                         Rectangle invalid = new Rectangle (0, top,
1424                                         Width, Height - top);
1425                         Invalidate (invalid);
1426                 }
1427
1428                 internal void UpdateNode (TreeNode node)
1429                 {
1430                         if (node == null)
1431                                 return;
1432
1433                         if (update_stack > 0) {
1434                                 update_needed = true;
1435                                 return;
1436                         }
1437
1438                         if (node == root_node) {
1439                                 Invalidate ();
1440                                 return;
1441                         }
1442
1443                         Rectangle invalid = new Rectangle (0, node.Bounds.Top - 1, Width,
1444                                         node.Bounds.Height + 1);
1445                         Invalidate (invalid);
1446                 }
1447
1448                 internal void UpdateNodePlusMinus (TreeNode node)
1449                 {
1450                         if (update_stack > 0) {
1451                                 update_needed = true;
1452                                 return;
1453                         }
1454
1455                         int l = node.Bounds.Left + 5;
1456
1457                         if (show_root_lines || node.Parent != null)
1458                                 l -= indent;
1459                         if (ImageList != null)
1460                                 l -= ImageList.ImageSize.Width + 3;
1461                         if (checkboxes)
1462                                 l -= 19;
1463
1464                         Invalidate (new Rectangle (l, node.Bounds.Top, 8, node.Bounds.Height));
1465                 }
1466
1467                 internal override void OnPaintInternal (PaintEventArgs pe)
1468                 {
1469                         Draw (pe.ClipRectangle, pe.Graphics);
1470                 }
1471
1472                 internal void CreateDashPen ()
1473                 {
1474                         dash = new Pen (LineColor, 1);
1475                         dash.DashStyle = DashStyle.Dot;
1476                 }
1477
1478                 private void Draw (Rectangle clip, Graphics dc)
1479                 {
1480                         dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), clip);
1481
1482                         if (dash == null)
1483                                 CreateDashPen ();
1484
1485                         Rectangle viewport = ViewportRectangle;
1486                         Rectangle original_clip = clip;
1487                         if (clip.Bottom > viewport.Bottom)
1488                                 clip.Height = viewport.Bottom - clip.Top;
1489
1490                         OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (TopNode);
1491                         while (walk.MoveNext ()) {
1492                                 TreeNode current = walk.CurrentNode;
1493
1494                                 // Haven't gotten to visible nodes yet
1495                                 if (current.GetY () + ActualItemHeight < clip.Top)
1496                                         continue;
1497
1498                                 // Past the visible nodes
1499                                 if (current.GetY () > clip.Bottom)
1500                                         break;
1501
1502                                 DrawTreeNode (current, dc, clip);
1503                         }
1504
1505                         if (hbar.Visible && vbar.Visible) {
1506                                 Rectangle corner = new Rectangle (hbar.Right, vbar.Bottom, vbar.Width, hbar.Height);
1507                                 if (original_clip.IntersectsWith (corner))
1508                                         dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorControl),
1509                                                         corner);
1510                         }
1511                 }
1512
1513 #if NET_2_0
1514                 private void DrawNodeState (TreeNode node, Graphics dc, int x, int y)
1515                 {
1516                         if (node.Checked) {
1517                                 if (StateImageList.Images[1] != null)
1518                                         dc.DrawImage (StateImageList.Images[1], new Rectangle (x, y, 16, 16));
1519                         } else {
1520                                 if (StateImageList.Images[0] != null)
1521                                         dc.DrawImage (StateImageList.Images[0], new Rectangle (x, y, 16, 16));
1522                         }
1523                 }
1524 #endif
1525
1526                 private void DrawNodeCheckBox (TreeNode node, Graphics dc, int x, int middle)
1527                 {
1528                         Pen pen = ThemeEngine.Current.ResPool.GetSizedPen(Color.Black, 2);
1529                                 dc.DrawRectangle (pen, x + 3, middle - 4, 11, 11);
1530
1531                         if (node.Checked) {
1532                                 Pen check_pen = ThemeEngine.Current.ResPool.GetPen(Color.Black);
1533                                 
1534                                 int check_size = 5;
1535                                 int lineWidth = 3;
1536                                 
1537                                 Rectangle rect = new Rectangle (x + 4, middle - 3, check_size, check_size);
1538                                 
1539                                 for (int i = 0; i < lineWidth; i++) {
1540                                         dc.DrawLine (check_pen, rect.Left + 1, rect.Top + lineWidth + i, rect.Left + 3, rect.Top + 5 + i);
1541                                         dc.DrawLine (check_pen, rect.Left + 3, rect.Top + 5 + i, rect.Left + 7, rect.Top + 1 + i);
1542                                 }
1543                         }
1544                 }
1545
1546                 private void DrawNodeLines (TreeNode node, Graphics dc, Rectangle clip, Pen dash, int x, int y, int middle)
1547                 {
1548                         int ladjust = 9;
1549                         int radjust = 0;
1550
1551                         if (node.nodes.Count > 0 && show_plus_minus)
1552                                 ladjust = 13;
1553                         if (checkboxes)
1554                                 radjust = 3;
1555
1556                         if (show_root_lines || node.Parent != null)
1557                                 dc.DrawLine (dash, x - indent + ladjust, middle, x + radjust, middle);
1558
1559                         if (node.PrevNode != null || node.Parent != null) {
1560                                 ladjust = 9;
1561                                 dc.DrawLine (dash, x - indent + ladjust, node.Bounds.Top,
1562                                                 x - indent + ladjust, middle - (show_plus_minus && node.Nodes.Count > 0 ? 4 : 0));
1563                         }
1564
1565                         if (node.NextNode != null) {
1566                                 ladjust = 9;
1567                                 dc.DrawLine (dash, x - indent + ladjust, middle + (show_plus_minus && node.Nodes.Count > 0 ? 4 : 0),
1568                                                 x - indent + ladjust, node.Bounds.Bottom);
1569                                 
1570                         }
1571
1572                         ladjust = 0;
1573                         if (show_plus_minus)
1574                                 ladjust = 9;
1575                         TreeNode parent = node.Parent;
1576                         while (parent != null) {
1577                                 if (parent.NextNode != null) {
1578                                         int px = parent.GetLinesX () - indent + ladjust;
1579                                         dc.DrawLine (dash, px, node.Bounds.Top, px, node.Bounds.Bottom);
1580                                 }
1581                                 parent = parent.Parent;
1582                         }
1583                 }
1584
1585                 private void DrawNodeImage (TreeNode node, Graphics dc, Rectangle clip, int x, int y)
1586                 {
1587                         if (!RectsIntersect (clip, x, y, ImageList.ImageSize.Width, ImageList.ImageSize.Height))
1588                                 return;
1589
1590                         int use_index = node.Image;
1591
1592                         if (use_index != -1)
1593                                 ImageList.Draw (dc, x, y, ImageList.ImageSize.Width, ImageList.ImageSize.Height, use_index);
1594                 }
1595
1596                 private void LabelEditFinished (object sender, EventArgs e)
1597                 {
1598                         EndEdit (edit_node);
1599                 }
1600
1601                 internal void BeginEdit (TreeNode node)
1602                 {
1603                         if (edit_node != null)
1604                                 EndEdit (edit_node);
1605
1606                         if (edit_text_box == null) {
1607                                 edit_text_box = new LabelEditTextBox ();
1608                                 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
1609                                 edit_text_box.Visible = false;
1610                                 edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled);
1611                                 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
1612                                 edit_text_box.TextChanged += new EventHandler (LabelTextChanged);
1613                                 Controls.Add (edit_text_box);
1614                         }
1615
1616                         node.EnsureVisible ();
1617
1618                         edit_text_box.Bounds = node.Bounds;
1619                         edit_text_box.Text = node.Text;
1620                         edit_text_box.Visible = true;
1621                         edit_text_box.Focus ();
1622                         edit_text_box.SelectAll ();
1623
1624                         edit_args = new NodeLabelEditEventArgs (node);
1625                         OnBeforeLabelEdit (edit_args);
1626
1627                         edit_node = node;
1628                         
1629                         if (edit_args.CancelEdit) {
1630                                 edit_node = null;
1631                                 EndEdit (node);
1632                         }
1633                 }
1634
1635                 private void LabelEditCancelled (object sender, EventArgs e)
1636                 {
1637                         edit_args.SetLabel (null);
1638                         EndEdit (edit_node);
1639                 }
1640
1641                 private void LabelTextChanged (object sender, EventArgs e)
1642                 {
1643                         int width = TextRenderer.MeasureTextInternal (edit_text_box.Text, edit_text_box.Font, false).Width + 4;
1644                         edit_text_box.Width = width;
1645
1646                         if (edit_args != null)
1647                                 edit_args.SetLabel (edit_text_box.Text);
1648                 }
1649
1650                 internal void EndEdit (TreeNode node)
1651                 {
1652                         if (edit_text_box != null && edit_text_box.Visible) {
1653                                 edit_text_box.Visible = false;
1654                                 Focus ();
1655                         }
1656
1657                         //
1658                         // If we get a call to BeginEdit from any AfterLabelEdit handler,
1659                         // the focus seems to always remain in the TreeView. This call seems
1660                         // to synchronize the focus events - I don't like it but it works
1661                         //
1662                         Application.DoEvents ();
1663
1664                         if (edit_node != null && edit_node == node) {
1665                                 edit_node = null;
1666
1667                                 NodeLabelEditEventArgs e = new NodeLabelEditEventArgs (edit_args.Node, edit_args.Label);
1668
1669                                 OnAfterLabelEdit (e);
1670
1671                                 if (e.CancelEdit)
1672                                         return;
1673
1674                                 if (e.Label != null)
1675                                         e.Node.Text = e.Label;
1676                         }
1677                         
1678                         // EndEdit ends editing even if not called on the editing node
1679                         edit_node = null;
1680                         UpdateNode (node);
1681                 }
1682
1683                 internal void CancelEdit (TreeNode node)
1684                 {
1685                         edit_args.SetLabel (null);
1686                         
1687                         if (edit_text_box != null && edit_text_box.Visible) {
1688                                 edit_text_box.Visible = false;
1689                                 Focus ();
1690                         }
1691
1692                         edit_node = null;
1693                         UpdateNode (node);
1694                 }
1695
1696                 internal int GetNodeWidth (TreeNode node)
1697                 {
1698                         Font font = node.NodeFont;
1699                         if (node.NodeFont == null)
1700                                 font = Font;
1701                         return (int)TextRenderer.MeasureString (node.Text, font, 0, string_format).Width + 3;
1702                 }
1703
1704                 private void DrawSelectionAndFocus(TreeNode node, Graphics dc, Rectangle r)
1705                 {
1706                         if (Focused && focused_node == node && !full_row_select) {
1707                                 ControlPaint.DrawFocusRectangle (dc, r, ForeColor, BackColor);
1708                         }
1709                         if (draw_mode != TreeViewDrawMode.Normal)
1710                                 return;
1711
1712                         r.Inflate (-1, -1);
1713                         if (Focused && node == highlighted_node) {
1714                                 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), r);
1715                         } else if (!hide_selection && node == highlighted_node) {
1716                                 dc.FillRectangle (SystemBrushes.Control, r);
1717                         } else {
1718                                 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (node.BackColor), r);
1719                         }
1720                 }
1721                  
1722                 private void DrawStaticNode (TreeNode node, Graphics dc)
1723                 {
1724                         if (!full_row_select || show_lines)
1725                                 DrawSelectionAndFocus(node, dc, node.Bounds);
1726
1727                         
1728                         Font font = node.NodeFont;
1729                         if (node.NodeFont == null)
1730                                 font = Font;
1731                         Color text_color = (Focused && node == highlighted_node ?
1732                                         ThemeEngine.Current.ColorHighlightText : node.ForeColor);
1733                         if (text_color.IsEmpty)
1734                                 text_color = ForeColor;
1735                         dc.DrawString (node.Text, font,
1736                                         ThemeEngine.Current.ResPool.GetSolidBrush (text_color),
1737                                         node.Bounds, string_format);
1738                 }
1739
1740                 private void DrawTreeNode (TreeNode node, Graphics dc, Rectangle clip)
1741                 {
1742                         int child_count = node.nodes.Count;
1743                         int y = node.GetY ();
1744                         int middle = y + (ActualItemHeight / 2);
1745
1746                         if (full_row_select && !show_lines) {
1747                                 Rectangle r = new Rectangle (1, y, ViewportRectangle.Width - 2, ActualItemHeight);
1748                                 DrawSelectionAndFocus (node, dc, r);
1749                         }
1750
1751                         if (draw_mode == TreeViewDrawMode.Normal || draw_mode == TreeViewDrawMode.OwnerDrawText) {
1752                                 if ((show_root_lines || node.Parent != null) && show_plus_minus && child_count > 0)
1753                                         ThemeEngine.Current.TreeViewDrawNodePlusMinus (this, node, dc, node.GetLinesX () - Indent + 5, middle);
1754
1755 #if NET_2_0
1756                                 if (checkboxes && state_image_list == null)
1757                                         DrawNodeCheckBox (node, dc, CheckBoxLeft (node) - 3, middle);
1758
1759                                 if (checkboxes && state_image_list != null)
1760                                         DrawNodeState (node, dc, CheckBoxLeft (node) - 3, y);
1761
1762                                 if (!checkboxes && node.StateImage != null)
1763                                         dc.DrawImage (node.StateImage, new Rectangle (CheckBoxLeft (node) - 3, y, 16, 16));
1764 #else
1765                                 if (checkboxes)
1766                                         DrawNodeCheckBox (node, dc, CheckBoxLeft (node) - 3, middle);
1767 #endif
1768
1769                                 if (show_lines)
1770                                         DrawNodeLines (node, dc, clip, dash, node.GetLinesX (), y, middle);
1771
1772                                 if (ImageList != null)
1773                                         DrawNodeImage (node, dc, clip, node.GetImageX (), y);
1774                         }
1775
1776                         
1777 #if NET_2_0
1778                         if (draw_mode != TreeViewDrawMode.Normal) {
1779                                 dc.FillRectangle (Brushes.White, node.Bounds);
1780                                 TreeNodeStates tree_node_state = TreeNodeStates.Default;;
1781                                 if (node.IsSelected)
1782                                         tree_node_state = TreeNodeStates.Selected;
1783                                 if (node.Checked)
1784                                         tree_node_state |= TreeNodeStates.Checked;
1785                                 if (node == focused_node)
1786                                         tree_node_state |= TreeNodeStates.Focused;
1787                                 Rectangle node_bounds = node.Bounds;
1788                                 if (draw_mode == TreeViewDrawMode.OwnerDrawText) {
1789                                         node_bounds.X += 3;
1790                                         node_bounds.Y += 1;
1791                                 } else {
1792                                         node_bounds.X = 0;
1793                                         node_bounds.Width = Width;
1794                                 }
1795
1796                                 DrawTreeNodeEventArgs e = new DrawTreeNodeEventArgs (dc, node, node_bounds, tree_node_state);
1797
1798                                 OnDrawNode (e);                         
1799                                 if (!e.DrawDefault)
1800                                         return;
1801                         }
1802 #endif
1803
1804                         if (!node.IsEditing)
1805                                 DrawStaticNode (node, dc);
1806                 }
1807
1808                 internal void UpdateScrollBars (bool force)
1809                 {
1810                         if (!force && (IsDisposed || update_stack > 0 || !IsHandleCreated || !Visible))
1811                                 return;
1812
1813                         bool vert = false;
1814                         bool horz = false;
1815                         int height = -1;
1816                         int width = -1;
1817
1818                         if (scrollable) {
1819                                 OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (root_node);
1820                                 
1821                                 while (walk.MoveNext ()) {
1822                                         int r = walk.CurrentNode.Bounds.Right;
1823                                         int b = walk.CurrentNode.Bounds.Bottom;
1824
1825                                         if (r > width)
1826                                                 width = r;
1827                                         if (b > height)
1828                                                 height = b;
1829                                 }
1830
1831                                 // Remove scroll adjustments
1832                                 if (nodes.Count > 0)
1833                                         height -= nodes [0].Bounds.Top;
1834                                 width += hbar_offset;
1835
1836                                 if (height > ClientRectangle.Height) {
1837                                         vert = true;
1838
1839                                         if (width > ClientRectangle.Width - SystemInformation.VerticalScrollBarWidth)
1840                                                 horz = true;
1841                                 } else if (width > ClientRectangle.Width) {
1842                                         horz = true;
1843                                 }
1844
1845                                 if (!vert && horz && height > ClientRectangle.Height - SystemInformation.HorizontalScrollBarHeight)
1846                                         vert = true;
1847                         }
1848
1849                         if (vert) {
1850                                 int visible_height = horz ? ClientRectangle.Height - hbar.Height : ClientRectangle.Height;
1851                                 vbar.SetValues (Math.Max (0, max_visible_order - 2), visible_height / ActualItemHeight);
1852                                 /*
1853                                 vbar.Maximum = max_visible_order;
1854                                 vbar.LargeChange = ClientRectangle.Height / ItemHeight;
1855                                 */
1856
1857                                 if (!vbar_bounds_set) {
1858                                         vbar.Bounds = new Rectangle (ClientRectangle.Width - vbar.Width, 0, vbar.Width,
1859                                                         ClientRectangle.Height -
1860                                                         (horz ? SystemInformation.VerticalScrollBarWidth : 0));
1861                                         vbar_bounds_set = true;
1862
1863                                         // We need to recalc the hbar if the vbar is now visible
1864                                         hbar_bounds_set = false;
1865                                 }
1866
1867                                 
1868                                 vbar.Visible = true;
1869                                 if (skipped_nodes > 0) {
1870                                         int skip = Math.Min (skipped_nodes, vbar.Maximum - VisibleCount + 1);
1871                                         skipped_nodes = 0;
1872                                         vbar.SafeValueSet (skip);
1873                                         skipped_nodes = skip;
1874                                 }
1875                         } else {
1876                                 skipped_nodes = 0;
1877                                 RecalculateVisibleOrder (root_node);
1878                                 vbar.Visible = false;
1879                                 vbar_bounds_set = false;
1880                         }
1881
1882                         if (horz) {
1883                                 hbar.SetValues (width + 1, ClientRectangle.Width - (vert ? SystemInformation.VerticalScrollBarWidth : 0));
1884                                 /*
1885                                 hbar.LargeChange = ClientRectangle.Width;
1886                                 hbar.Maximum = width + 1;
1887                                 */
1888
1889                                 if (!hbar_bounds_set) {
1890                                         hbar.Bounds = new Rectangle (0, ClientRectangle.Height - hbar.Height,
1891                                                         ClientRectangle.Width - (vert ? SystemInformation.VerticalScrollBarWidth : 0),
1892                                                         hbar.Height);
1893                                         hbar_bounds_set = true;
1894                                 }
1895                                 hbar.Visible = true;
1896                         } else {
1897                                 hbar_offset = 0;
1898                                 hbar.Visible = false;
1899                                 hbar_bounds_set = false;
1900                         }
1901                 }
1902
1903                 private void SizeChangedHandler (object sender, EventArgs e)
1904                 {
1905                         if (IsHandleCreated) {
1906                                 if (max_visible_order == -1)
1907                                         RecalculateVisibleOrder (root_node);
1908                                 UpdateScrollBars (false);
1909                         }
1910
1911                         if (vbar.Visible) {
1912                                 vbar.Bounds = new Rectangle (ClientRectangle.Width - vbar.Width, 0, vbar.Width,
1913                                                 ClientRectangle.Height - (hbar.Visible ? SystemInformation.HorizontalScrollBarHeight : 0));
1914                         }
1915
1916                         if (hbar.Visible) {
1917                                 hbar.Bounds = new Rectangle (0, ClientRectangle.Height - hbar.Height,
1918                                                 ClientRectangle.Width - (vbar.Visible ? SystemInformation.VerticalScrollBarWidth : 0), hbar.Height);
1919                         }
1920                 }
1921
1922                 private void VScrollBarValueChanged (object sender, EventArgs e)
1923                 {
1924                         EndEdit (edit_node);
1925
1926                         SetVScrollPos (vbar.Value, null);
1927                 }
1928
1929                 private void SetVScrollPos (int pos, TreeNode new_top)
1930                 {
1931                         if (pos < 0)
1932                                 pos = 0;
1933
1934                         if (skipped_nodes == pos)
1935                                 return;
1936
1937                         int diff = skipped_nodes - pos;
1938                         skipped_nodes = pos;
1939
1940                         if (!IsHandleCreated)
1941                                 return;
1942
1943                         int y_move = diff * ActualItemHeight;
1944                         XplatUI.ScrollWindow (Handle, ViewportRectangle, 0, y_move, false);
1945                 }
1946
1947                 /*private void SetVScrollTop (TreeNode new_top)
1948                 {
1949                         vbar.Value = new_top.visible_order - VisibleCount;
1950                 }*/
1951
1952                 private void HScrollBarValueChanged(object sender, EventArgs e)
1953                 {
1954                         EndEdit (edit_node);
1955
1956                         int old_offset = hbar_offset;
1957                         hbar_offset = hbar.Value;
1958
1959                         if (hbar_offset < 0) {
1960                                 hbar_offset = 0;
1961                         }
1962
1963                         XplatUI.ScrollWindow (Handle, ViewportRectangle, old_offset - hbar_offset, 0, false);
1964                 }
1965
1966                 internal void ExpandBelow (TreeNode node, int count_to_next)
1967                 {
1968                         if (update_stack > 0) {
1969                                 update_needed = true;
1970                                 return;
1971                         }
1972
1973                         // If node Bottom is less than 0, the node is above and not visible,
1974                         // and we need to scroll the entire viewport
1975                         int node_bottom = node.Bounds.Bottom >= 0 ? node.Bounds.Bottom : 0;
1976                         Rectangle below = new Rectangle (0, node_bottom, ViewportRectangle.Width,
1977                                         ViewportRectangle.Height - node_bottom);
1978
1979                         int amount = count_to_next * ActualItemHeight;
1980
1981                         if (amount > 0)
1982                                 XplatUI.ScrollWindow (Handle, below, 0, amount, false);
1983
1984                         if (show_plus_minus) {
1985                                 Invalidate (new Rectangle (0, node.GetY (), Width, ActualItemHeight));
1986                         }
1987                 }
1988
1989                 internal void CollapseBelow (TreeNode node, int count_to_next)
1990                 {
1991                         if (update_stack > 0) {
1992                                 update_needed = true;
1993                                 return;
1994                         }
1995
1996                         Rectangle below = new Rectangle (0, node.Bounds.Bottom, ViewportRectangle.Width,
1997                                         ViewportRectangle.Height - node.Bounds.Bottom);
1998
1999                         int amount = count_to_next * ActualItemHeight;
2000
2001                         if (amount > 0)
2002                                 XplatUI.ScrollWindow (Handle, below, 0, -amount, false);
2003
2004                         if (show_plus_minus) {
2005                                 Invalidate (new Rectangle (0, node.GetY (), Width, ActualItemHeight));
2006                         }
2007                 }
2008
2009                 private void MouseWheelHandler(object sender, MouseEventArgs e) {
2010
2011                         if (vbar == null || !vbar.is_visible) {
2012                                 return;
2013                         }
2014
2015                         if (e.Delta < 0) {
2016                                 vbar.Value = Math.Min(vbar.Value + SystemInformation.MouseWheelScrollLines, vbar.Maximum - VisibleCount + 1);
2017                         } else {
2018                                 vbar.Value = Math.Max(0, vbar.Value - SystemInformation.MouseWheelScrollLines);
2019                         }
2020                 }
2021
2022                 private void VisibleChangedHandler (object sender, EventArgs e)
2023                 {
2024                         if (Visible) {
2025                                 UpdateScrollBars (false);
2026                         }
2027                 }
2028
2029                 private void FontChangedHandler (object sender, EventArgs e)
2030                 {
2031                         if (IsHandleCreated) {
2032                                 TreeNode top = TopNode;
2033                                 InvalidateNodeWidthRecursive (root_node);
2034
2035                                 SetTop (top);
2036                         }
2037                 }
2038
2039                 private void InvalidateNodeWidthRecursive (TreeNode node)
2040                 {
2041                         node.InvalidateWidth ();
2042                         foreach (TreeNode child in node.Nodes) {
2043                                 InvalidateNodeWidthRecursive (child);
2044                         }
2045                 }
2046
2047                 private void GotFocusHandler (object sender, EventArgs e)
2048                 {
2049                         if (selected_node == null) {
2050                                 if (pre_selected_node != null) {
2051                                         SelectedNode = pre_selected_node;
2052                                         return;
2053                                 }
2054                                 
2055                                 SelectedNode = TopNode;
2056                         
2057                         } else if (selected_node != null)
2058                                 UpdateNode (selected_node);
2059                 }
2060
2061                 private void LostFocusHandler (object sender, EventArgs e)
2062                 {
2063                         UpdateNode (SelectedNode);
2064                 }
2065
2066                 private void MouseDownHandler (object sender, MouseEventArgs e)
2067                 {
2068                         if (e.Button == MouseButtons.Right)
2069                                 Focus ();
2070
2071                         TreeNode node = GetNodeAt (e.Y);
2072                         if (node == null)
2073                                 return;
2074
2075 #if NET_2_0
2076                         mouse_click_node = node;
2077 #endif
2078
2079                         if (show_plus_minus && IsPlusMinusArea (node, e.X) && e.Button == MouseButtons.Left) {
2080                                 node.Toggle ();
2081                                 return;
2082                         } else if (checkboxes && IsCheckboxArea (node, e.X) && e.Button == MouseButtons.Left) {
2083                                 node.check_reason = TreeViewAction.ByMouse;
2084                                 node.Checked = !node.Checked;
2085                                 UpdateNode(node);
2086                                 return;
2087                         } else if (IsSelectableArea (node, e.X) || full_row_select) {
2088                                 TreeNode old_highlighted = highlighted_node;
2089                                 highlighted_node = node;
2090                                 if (label_edit && e.Clicks == 1 && highlighted_node == old_highlighted && e.Button == MouseButtons.Left) {
2091                                         BeginEdit (node);
2092                                 } else if (highlighted_node != focused_node) {
2093                                         Size ds = SystemInformation.DragSize;
2094                                         mouse_rect.X = e.X - ds.Width;
2095                                         mouse_rect.Y = e.Y - ds.Height;
2096                                         mouse_rect.Width = ds.Width * 2;
2097                                         mouse_rect.Height = ds.Height * 2;
2098
2099                                         select_mmove = true;
2100                                 }
2101
2102                                 Invalidate (highlighted_node.Bounds);
2103                                 if (old_highlighted != null)
2104                                         Invalidate (Bloat (old_highlighted.Bounds));
2105                         } 
2106                 }
2107
2108                 private void MouseUpHandler (object sender, MouseEventArgs e) {
2109 #if NET_2_0
2110                         TreeNode node = GetNodeAt (e.Y);
2111                         
2112                         if (node != null && node == mouse_click_node) {
2113                                 if (e.Clicks == 2)
2114                                         OnNodeMouseDoubleClick (new TreeNodeMouseClickEventArgs (node, e.Button, e.Clicks, e.X, e.Y));
2115                                 else
2116                                         OnNodeMouseClick (new TreeNodeMouseClickEventArgs (node, e.Button, e.Clicks, e.X, e.Y));
2117                         }
2118                         
2119                         mouse_click_node = null;
2120 #endif
2121
2122                         drag_begin_x = -1;
2123                         drag_begin_y = -1;
2124
2125                         if (!select_mmove)
2126                                 return;
2127
2128                         select_mmove = false;
2129
2130                         if (e.Button == MouseButtons.Right && selected_node != null) {
2131                                 Invalidate (highlighted_node.Bounds);
2132                                 highlighted_node = selected_node;
2133                                 Invalidate (selected_node.Bounds);
2134                                 return;
2135                         }
2136
2137                         TreeViewCancelEventArgs ce = new TreeViewCancelEventArgs (highlighted_node, false, TreeViewAction.ByMouse);
2138                         OnBeforeSelect (ce);
2139
2140                         Rectangle invalid;
2141                         if (!ce.Cancel) {
2142                                 TreeNode prev_focused_node = focused_node;
2143                                 TreeNode prev_highlighted_node = highlighted_node;
2144                                 
2145                                 selected_node = highlighted_node;
2146                                 focused_node = highlighted_node;
2147                                 OnAfterSelect (new TreeViewEventArgs (selected_node, TreeViewAction.ByMouse));
2148
2149                                 if (prev_focused_node != null) {
2150                                         invalid = Rectangle.Union (Bloat (prev_focused_node.Bounds),
2151                                                         Bloat (prev_highlighted_node.Bounds));
2152                                 } else {
2153                                         invalid = Bloat (prev_highlighted_node.Bounds);
2154                                 }
2155
2156                                 invalid.X = 0;
2157                                 invalid.Width = ViewportRectangle.Width;
2158
2159                                 Invalidate (invalid);
2160                         } else {
2161                                 highlighted_node = focused_node;
2162                                 selected_node = focused_node;
2163                         }
2164                 }
2165
2166                 private void MouseMoveHandler (object sender, MouseEventArgs e) {
2167 #if NET_2_0
2168                         // XXX - This should use HitTest and only fire when we are over
2169                         // the important parts of a node, not things like gridlines or
2170                         // whitespace
2171                         TreeNode tn = GetNodeAt (e.Location);
2172                         
2173                         if (tn != tooltip_currently_showing)
2174                                 MouseLeftItem (tooltip_currently_showing);
2175                                 
2176                         if (tn != null && tn != tooltip_currently_showing)
2177                                 MouseEnteredItem (tn);
2178 #endif
2179                         
2180                         if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right) {
2181                                 if (drag_begin_x == -1 && drag_begin_y == -1) {
2182                                         drag_begin_x = e.X;
2183                                         drag_begin_y = e.Y;
2184                                 } else {
2185                                         double rise = Math.Pow (drag_begin_x - e.X, 2);
2186                                         double run = Math.Pow (drag_begin_y - e.Y, 2);
2187                                         double move = Math.Sqrt (rise + run);
2188                                         if (move > 3) {
2189                                                 TreeNode drag = GetNodeAtUseX (e.X, e.Y);
2190                                                 
2191                                                 if (drag != null) {
2192                                                         OnItemDrag (new ItemDragEventArgs (e.Button, drag));
2193                                                 }
2194                                                 drag_begin_x = -1;
2195                                                 drag_begin_y = -1;
2196                                         }
2197                                 }
2198                                 
2199                         }
2200
2201                         // If there is enough movement before the mouse comes up,
2202                         // selection is reverted back to the originally selected node
2203                         if (!select_mmove || mouse_rect.Contains (e.X, e.Y))
2204                                 return;
2205
2206                         Invalidate (highlighted_node.Bounds);
2207                         Invalidate (selected_node.Bounds);
2208                         Invalidate (focused_node.Bounds);
2209
2210                         highlighted_node = selected_node;
2211                         focused_node = selected_node;
2212
2213                         select_mmove = false;
2214                 }
2215
2216                 private void DoubleClickHandler (object sender, MouseEventArgs e) {
2217                         TreeNode node = GetNodeAtUseX (e.X,e.Y);
2218                         if(node != null) {
2219                                 node.Toggle();
2220                         }
2221                 }
2222
2223                 
2224                 private bool RectsIntersect (Rectangle r, int left, int top, int width, int height)
2225                 {
2226                         return !((r.Left > left + width) || (r.Right < left) ||
2227                                         (r.Top > top + height) || (r.Bottom < top));
2228                 }
2229
2230 #if NET_2_0
2231                 // Return true if message was handled, false to send it to base
2232                 private bool WmContextMenu (ref Message m)
2233                 {
2234                         Point pt;
2235                         TreeNode tn;
2236                         
2237                         pt = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ()));
2238
2239                         // This means it's a keyboard menu request
2240                         if (pt.X == -1 || pt.Y == -1) {
2241                                 tn = SelectedNode;
2242                                 
2243                                 if (tn == null)
2244                                         return false;
2245                                 
2246                                 pt = new Point (tn.Bounds.Left, tn.Bounds.Top + (tn.Bounds.Height / 2));
2247                         } else {
2248                                 pt = PointToClient (pt);
2249                                 
2250                                 tn = GetNodeAt (pt);
2251
2252                                 if (tn == null)
2253                                         return false;
2254                         }
2255                         
2256                         // At this point, we have a valid TreeNode
2257                         if (tn.ContextMenu != null) {
2258                                 tn.ContextMenu.Show (this, pt);
2259                                 return true;
2260                         } else if (tn.ContextMenuStrip != null) {
2261                                 tn.ContextMenuStrip.Show (this, pt);
2262                                 return true;
2263                         }
2264                         
2265                         // The node we found did not have its own menu, let the parent try to display its menu
2266                         return false;
2267                 }
2268 #endif
2269
2270                 #region Stuff for ToolTips
2271 #if NET_2_0
2272                 private void MouseEnteredItem (TreeNode item)
2273                 {
2274                         tooltip_currently_showing = item;
2275                         
2276                         if (!is_hovering)
2277                                 return;
2278
2279                         if (ShowNodeToolTips && !string.IsNullOrEmpty (tooltip_currently_showing.ToolTipText))
2280                                 ToolTipWindow.Present (this, tooltip_currently_showing.ToolTipText);
2281
2282                         OnNodeMouseHover (new TreeNodeMouseHoverEventArgs (tooltip_currently_showing));
2283                 }
2284
2285                 private void MouseLeftItem (TreeNode item)
2286                 {
2287                         ToolTipWindow.Hide (this);
2288                         tooltip_currently_showing = null;
2289                 }
2290
2291                 private ToolTip ToolTipWindow {
2292                         get {
2293                                 if (tooltip_window == null)
2294                                         tooltip_window = new ToolTip ();
2295
2296                                 return tooltip_window;
2297                         }
2298                 }
2299 #endif
2300                 #endregion
2301                 
2302                 #endregion      // Internal & Private Methods and Properties
2303
2304                 #region Events
2305                 static object ItemDragEvent = new object ();
2306                 static object AfterCheckEvent = new object ();
2307                 static object AfterCollapseEvent = new object ();
2308                 static object AfterExpandEvent = new object ();
2309                 static object AfterLabelEditEvent = new object ();
2310                 static object AfterSelectEvent = new object ();
2311                 static object BeforeCheckEvent = new object ();
2312                 static object BeforeCollapseEvent = new object ();
2313                 static object BeforeExpandEvent = new object ();
2314                 static object BeforeLabelEditEvent = new object ();
2315                 static object BeforeSelectEvent = new object ();
2316 #if NET_2_0
2317                 static object DrawNodeEvent = new object ();
2318                 static object NodeMouseClickEvent = new object ();
2319                 static object NodeMouseDoubleClickEvent = new object();
2320                 static object NodeMouseHoverEvent = new object ();
2321                 static object RightToLeftLayoutChangedEvent = new object ();
2322 #endif
2323
2324                 public event ItemDragEventHandler ItemDrag {
2325                         add { Events.AddHandler (ItemDragEvent, value); }
2326                         remove { Events.RemoveHandler (ItemDragEvent, value); }
2327                 }
2328
2329                 public event TreeViewEventHandler AfterCheck {
2330                         add { Events.AddHandler (AfterCheckEvent, value); }
2331                         remove { Events.RemoveHandler (AfterCheckEvent, value); }
2332                 }
2333
2334                 public event TreeViewEventHandler AfterCollapse {
2335                         add { Events.AddHandler (AfterCollapseEvent, value); }
2336                         remove { Events.RemoveHandler (AfterCollapseEvent, value); }
2337                 }
2338
2339                 public event TreeViewEventHandler AfterExpand {
2340                         add { Events.AddHandler (AfterExpandEvent, value); }
2341                         remove { Events.RemoveHandler (AfterExpandEvent, value); }
2342                 }
2343
2344                 public event NodeLabelEditEventHandler AfterLabelEdit {
2345                         add { Events.AddHandler (AfterLabelEditEvent, value); }
2346                         remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
2347                 }
2348
2349                 public event TreeViewEventHandler AfterSelect {
2350                         add { Events.AddHandler (AfterSelectEvent, value); }
2351                         remove { Events.RemoveHandler (AfterSelectEvent, value); }
2352                 }
2353
2354                 public event TreeViewCancelEventHandler BeforeCheck {
2355                         add { Events.AddHandler (BeforeCheckEvent, value); }
2356                         remove { Events.RemoveHandler (BeforeCheckEvent, value); }
2357                 }
2358
2359                 public event TreeViewCancelEventHandler BeforeCollapse {
2360                         add { Events.AddHandler (BeforeCollapseEvent, value); }
2361                         remove { Events.RemoveHandler (BeforeCollapseEvent, value); }
2362                 }
2363
2364                 public event TreeViewCancelEventHandler BeforeExpand {
2365                         add { Events.AddHandler (BeforeExpandEvent, value); }
2366                         remove { Events.RemoveHandler (BeforeExpandEvent, value); }
2367                 }
2368
2369                 public event NodeLabelEditEventHandler BeforeLabelEdit {
2370                         add { Events.AddHandler (BeforeLabelEditEvent, value); }
2371                         remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
2372                 }
2373
2374                 public event TreeViewCancelEventHandler BeforeSelect {
2375                         add { Events.AddHandler (BeforeSelectEvent, value); }
2376                         remove { Events.RemoveHandler (BeforeSelectEvent, value); }
2377                 }
2378
2379 #if NET_2_0
2380                 public event DrawTreeNodeEventHandler DrawNode {
2381                         add { Events.AddHandler (DrawNodeEvent, value); }
2382                         remove { Events.RemoveHandler (DrawNodeEvent, value); }
2383                 }
2384
2385                 public event TreeNodeMouseClickEventHandler NodeMouseClick {
2386                         add { Events.AddHandler (NodeMouseClickEvent, value); }
2387                         remove { Events.RemoveHandler (NodeMouseClickEvent, value); }
2388                 }
2389
2390
2391                 public event TreeNodeMouseClickEventHandler NodeMouseDoubleClick {
2392                         add { Events.AddHandler (NodeMouseDoubleClickEvent, value); }
2393                         remove { Events.RemoveHandler (NodeMouseDoubleClickEvent, value); }
2394                 }
2395                 
2396                 public event TreeNodeMouseHoverEventHandler NodeMouseHover {
2397                         add { Events.AddHandler (NodeMouseHoverEvent, value); }
2398                         remove { Events.RemoveHandler (NodeMouseHoverEvent, value); }
2399                 }
2400                 
2401                 public event EventHandler RightToLeftLayoutChanged {
2402                         add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); }
2403                         remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); }
2404                 }
2405 #endif
2406
2407                 [Browsable (false)]
2408                 [EditorBrowsable (EditorBrowsableState.Never)]  
2409                 public new event EventHandler BackgroundImageChanged {
2410                         add { base.BackgroundImageChanged += value; }
2411                         remove { base.BackgroundImageChanged -= value; }
2412                 }
2413
2414 #if NET_2_0
2415                 [Browsable (false)]
2416                 [EditorBrowsable (EditorBrowsableState.Never)]
2417                 public new event EventHandler BackgroundImageLayoutChanged {
2418                         add { base.BackgroundImageLayoutChanged += value; }
2419                         remove { base.BackgroundImageLayoutChanged -= value; }
2420                 }
2421
2422                 [Browsable (false)]
2423                 [EditorBrowsable (EditorBrowsableState.Never)]
2424                 public new event EventHandler PaddingChanged {
2425                         add { base.PaddingChanged += value; }
2426                         remove { base.PaddingChanged -= value; }
2427                 }
2428 #endif
2429
2430                 [EditorBrowsable (EditorBrowsableState.Never)]  
2431                 [Browsable (false)]
2432                 public new event PaintEventHandler Paint {
2433                         add { base.Paint += value; }
2434                         remove { base.Paint -= value; }
2435                 }
2436
2437                 [EditorBrowsable (EditorBrowsableState.Never)]  
2438                 [Browsable (false)]
2439                 public new event EventHandler TextChanged {
2440                         add { base.TextChanged += value; }
2441                         remove { base.TextChanged -= value; }
2442                 }
2443                 #endregion      // Events
2444         }
2445 }
2446
2447