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