f87673ec6aafc4d890cec284221df50eeb6f4365
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / TreeView.cs
1 //
2 // System.Web.UI.WebControls.TreeView.cs
3 //
4 // Authors:
5 //      Lluis Sanchez Gual (lluis@novell.com)
6 //
7 // (C) 2004 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
29 //
30
31 #if NET_2_0
32
33 using System.Collections;
34 using System.Text;
35 using System.ComponentModel;
36 using System.Globalization;
37 using System.Web.Handlers;
38 using System.Collections.Specialized;
39 using System.IO;
40 using System.Security.Permissions;
41 using System.Collections.Generic;
42
43 namespace System.Web.UI.WebControls
44 {
45         // CAS
46         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
48         // attributes
49         [SupportsEventValidation]
50         [ControlValueProperty ("SelectedValue")]
51         [DefaultEvent ("SelectedNodeChanged")]
52         [Designer ("System.Web.UI.Design.WebControls.TreeViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
53         public class TreeView: HierarchicalDataBoundControl, IPostBackEventHandler, IPostBackDataHandler, ICallbackEventHandler
54         {
55                 string activeSiteMapPath;
56                 bool stylesPrepared;
57                 Style hoverNodeStyle;
58                 TreeNodeStyle leafNodeStyle;
59                 TreeNodeStyle nodeStyle;
60                 TreeNodeStyle parentNodeStyle;
61                 TreeNodeStyle rootNodeStyle;
62                 TreeNodeStyle selectedNodeStyle;
63                 
64                 TreeNodeStyleCollection levelStyles;
65                 TreeNodeCollection nodes;
66                 TreeNodeBindingCollection dataBindings;
67                 
68                 TreeNode selectedNode;
69                 Hashtable bindings;
70
71                 int registeredStylesCounter = -1;
72                 List<Style> levelLinkStyles;
73                 Style controlLinkStyle;
74                 Style nodeLinkStyle;
75                 Style rootNodeLinkStyle;
76                 Style parentNodeLinkStyle;
77                 Style leafNodeLinkStyle;
78                 Style selectedNodeLinkStyle;
79                 Style hoverNodeLinkStyle;
80                 
81                 static readonly object TreeNodeCheckChangedEvent = new object();
82                 static readonly object SelectedNodeChangedEvent = new object();
83                 static readonly object TreeNodeCollapsedEvent = new object();
84                 static readonly object TreeNodeDataBoundEvent = new object();
85                 static readonly object TreeNodeExpandedEvent = new object();
86                 static readonly object TreeNodePopulateEvent = new object();
87                 
88                 static Hashtable imageStyles = new Hashtable ();
89
90                 class TreeViewExpandDepthConverter : TypeConverter
91                 {
92                         public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
93                         {
94                                 if (sourceType == typeof (string) || sourceType == typeof (int))
95                                         return true;
96
97                                 return base.CanConvertFrom (context, sourceType);
98                         }
99
100                         public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
101                         {
102                                 if (destinationType == typeof (string) || destinationType == typeof (int))
103                                         return true;
104
105                                 return base.CanConvertTo (context, destinationType);
106                         }
107
108                         public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
109                         {
110                                 if (destinationType != typeof (int) && destinationType != typeof (string))
111                                         return base.ConvertTo (context, culture, value, destinationType);
112                                 
113                                 if (value is string) {
114                                         if (destinationType == typeof (int)) {
115                                                 if (String.Compare ("FullyExpand", (string)value, StringComparison.OrdinalIgnoreCase) == 0)
116                                                         return -1;
117                                                 
118                                                 try {
119                                                         return Int32.Parse ((string)value);
120                                                 } catch (Exception) {
121                                                         return -1;
122                                                 }
123                                         } else
124                                                 return value;   
125                                 }
126
127                                 int val = (int)value;
128                                 if (destinationType == typeof (string)) {
129                                         if (val == -1)
130                                                 return "FullyExpand";
131                                         return val.ToString ();
132                                 }
133                                         
134                                 return value;
135                         }
136
137                         public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value)
138                         {
139                                 if (!(value is string) && !(value is int))
140                                         return base.ConvertFrom (context, culture, value);
141
142                                 if (value is string) {
143                                         if (String.Compare ("FullyExpand", (string)value, StringComparison.OrdinalIgnoreCase) == 0)
144                                                 return -1;
145
146                                         try {
147                                                 return Int32.Parse ((string)value);
148                                         } catch (Exception) {
149                                                 return null;
150                                         }
151                                 }
152
153                                 return value;
154                         }
155                 }
156                 
157                 class ImageStyle
158                 {
159                         public ImageStyle (string expand, string collapse, string noExpand, string icon, string iconLeaf, string iconRoot) {
160                                 Expand = expand;
161                                 Collapse = collapse;
162                                 NoExpand = noExpand;
163                                 RootIcon = iconRoot;
164                                 ParentIcon = icon;
165                                 LeafIcon = iconLeaf;
166                         }
167                         
168                         public string Expand;
169                         public string Collapse;
170                         public string NoExpand;
171                         public string RootIcon;
172                         public string ParentIcon;
173                         public string LeafIcon;
174                 }
175                 
176                 static TreeView ()
177                 {
178                         imageStyles [TreeViewImageSet.Arrows] = new ImageStyle ("arrow_plus", "arrow_minus", "arrow_noexpand", null, null, null);
179                         imageStyles [TreeViewImageSet.BulletedList] = new ImageStyle (null, null, null, "dot_full", "dot_empty", "dot_full");
180                         imageStyles [TreeViewImageSet.BulletedList2] = new ImageStyle (null, null, null, "box_full", "box_empty", "box_full");
181                         imageStyles [TreeViewImageSet.BulletedList3] = new ImageStyle (null, null, null, "star_full", "star_empty", "star_full");
182                         imageStyles [TreeViewImageSet.BulletedList4] = new ImageStyle (null, null, null, "star_full", "star_empty", "dots");
183                         imageStyles [TreeViewImageSet.Contacts] = new ImageStyle ("TreeView_plus", "TreeView_minus", "contact", null, null, null);
184                         imageStyles [TreeViewImageSet.Events] = new ImageStyle (null, null, null, "warning", "warning", "warning");
185                         imageStyles [TreeViewImageSet.Inbox] = new ImageStyle (null, null, null, "inbox", "inbox", "inbox");
186                         imageStyles [TreeViewImageSet.Msdn] = new ImageStyle ("box_plus", "box_minus", "box_noexpand", null, null, null);
187                         imageStyles [TreeViewImageSet.Simple] = new ImageStyle (null, null, "box_full", null, null, null);
188                         imageStyles [TreeViewImageSet.Simple2] = new ImageStyle (null, null, "box_empty", null, null, null);
189
190                         // TODO
191                         imageStyles [TreeViewImageSet.News] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
192                         imageStyles [TreeViewImageSet.Faq] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
193                         imageStyles [TreeViewImageSet.WindowsHelp] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
194                         imageStyles [TreeViewImageSet.XPFileExplorer] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", "folder", "file", "computer");
195                 }
196                 
197                 public event TreeNodeEventHandler TreeNodeCheckChanged {
198                         add { Events.AddHandler (TreeNodeCheckChangedEvent, value); }
199                         remove { Events.RemoveHandler (TreeNodeCheckChangedEvent, value); }
200                 }
201                 
202                 public event EventHandler SelectedNodeChanged {
203                         add { Events.AddHandler (SelectedNodeChangedEvent, value); }
204                         remove { Events.RemoveHandler (SelectedNodeChangedEvent, value); }
205                 }
206                 
207                 public event TreeNodeEventHandler TreeNodeCollapsed {
208                         add { Events.AddHandler (TreeNodeCollapsedEvent, value); }
209                         remove { Events.RemoveHandler (TreeNodeCollapsedEvent, value); }
210                 }
211                 
212                 public event TreeNodeEventHandler TreeNodeDataBound {
213                         add { Events.AddHandler (TreeNodeDataBoundEvent, value); }
214                         remove { Events.RemoveHandler (TreeNodeDataBoundEvent, value); }
215                 }
216                 
217                 public event TreeNodeEventHandler TreeNodeExpanded {
218                         add { Events.AddHandler (TreeNodeExpandedEvent, value); }
219                         remove { Events.RemoveHandler (TreeNodeExpandedEvent, value); }
220                 }
221                 
222                 public event TreeNodeEventHandler TreeNodePopulate {
223                         add { Events.AddHandler (TreeNodePopulateEvent, value); }
224                         remove { Events.RemoveHandler (TreeNodePopulateEvent, value); }
225                 }
226                 
227                 protected virtual void OnTreeNodeCheckChanged (TreeNodeEventArgs e)
228                 {
229                         if (Events != null) {
230                                 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCheckChangedEvent];
231                                 if (eh != null) eh (this, e);
232                         }
233                 }
234
235                 protected virtual void OnSelectedNodeChanged (EventArgs e)
236                 {
237                         if (Events != null) {
238                                 EventHandler eh = (EventHandler) Events [SelectedNodeChangedEvent];
239                                 if (eh != null) eh (this, e);
240                         }
241                 }
242
243                 protected virtual void OnTreeNodeCollapsed (TreeNodeEventArgs e)
244                 {
245                         if (Events != null) {
246                                 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCollapsedEvent];
247                                 if (eh != null) eh (this, e);
248                         }
249                 }
250
251                 protected virtual void OnTreeNodeDataBound (TreeNodeEventArgs e)
252                 {
253                         if (Events != null) {
254                                 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeDataBoundEvent];
255                                 if (eh != null) eh (this, e);
256                         }
257                 }
258
259                 protected virtual void OnTreeNodeExpanded (TreeNodeEventArgs e)
260                 {
261                         if (Events != null) {
262                                 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeExpandedEvent];
263                                 if (eh != null) eh (this, e);
264                         }
265                 }
266
267                 protected virtual void OnTreeNodePopulate (TreeNodeEventArgs e)
268                 {
269                         if (Events != null) {
270                                 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodePopulateEvent];
271                                 if (eh != null) eh (this, e);
272                         }
273                 }
274
275
276                 [Localizable (true)]
277                 public string CollapseImageToolTip {
278                         get {
279                                 return ViewState.GetString ("CollapseImageToolTip", "Collapse {0}");
280                         }
281                         set {
282                                 ViewState["CollapseImageToolTip"] = value;
283                         }
284                 }
285
286                 [MonoTODO ("Implement support for this")]
287                 [WebCategory ("Behavior")]
288                 [WebSysDescription ("Whether the tree will automatically generate bindings.")]
289                 [DefaultValue (true)]
290                 public bool AutoGenerateDataBindings {
291                         get {
292                                 return ViewState.GetBool ("AutoGenerateDataBindings", true);
293                         }
294                         set {
295                                 ViewState["AutoGenerateDataBindings"] = value;
296                         }
297                 }
298
299                 [DefaultValue ("")]
300                 [WebSysDescription ("The url of the image to show when a node can be collapsed.")]
301                 [UrlProperty]
302                 [WebCategory ("Appearance")]
303                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
304                 public string CollapseImageUrl {
305                         get {
306                                 return ViewState.GetString ("CollapseImageUrl", "");
307                         }
308                         set {
309                                 ViewState["CollapseImageUrl"] = value;
310                         }
311                 }
312
313                 [WebCategory ("Data")]
314                 [PersistenceMode (PersistenceMode.InnerProperty)]
315                 [WebSysDescription ("Bindings for tree nodes.")]
316                 [Editor ("System.Web.UI.Design.WebControls.TreeViewBindingsEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
317                 [DefaultValue (null)]
318                 [MergablePropertyAttribute (false)]
319                 public TreeNodeBindingCollection DataBindings {
320                         get {
321                                 if (dataBindings == null) {
322                                         dataBindings = new TreeNodeBindingCollection ();
323                                         if (IsTrackingViewState)
324                                                 ((IStateManager)dataBindings).TrackViewState();
325                                 }
326                                 return dataBindings;
327                         }
328                 }
329
330                 [WebCategory ("Behavior")]
331                 [WebSysDescription ("Whether the tree view can use client-side script to expand and collapse nodes.")]
332                 [Themeable (false)]
333                 [DefaultValue (true)]
334                 public bool EnableClientScript {
335                         get {
336                                 return ViewState.GetBool ("EnableClientScript", true);
337                         }
338                         set {
339                                 ViewState["EnableClientScript"] = value;
340                         }
341                 }
342
343                 [DefaultValue (-1)]
344                 [WebCategory ("Behavior")]
345                 [WebSysDescription ("The initial expand depth.")]
346                 [TypeConverter ("System.Web.UI.WebControls.TreeView+TreeViewExpandDepthConverter, " + Consts.AssemblySystem_Web)]
347                 public int ExpandDepth {
348                         get {
349                                 return ViewState.GetInt ("ExpandDepth", -1);
350                         }
351                         set {
352                                 ViewState["ExpandDepth"] = value;
353                         }
354                 }
355
356                 [Localizable (true)]
357                 public string ExpandImageToolTip {
358                         get {
359                                 return ViewState.GetString ("ExpandImageToolTip", "Expand {0}");
360                         }
361                         set {
362                                 ViewState["ExpandImageToolTip"] = value;
363                         }
364                 }
365
366                 [DefaultValue ("")]
367                 [UrlProperty]
368                 [WebSysDescription ("The url of the image to show when a node can be expanded.")]
369                 [WebCategory ("Appearance")]
370                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
371                 public string ExpandImageUrl {
372                         get {
373                                 return ViewState.GetString ("ExpandImageUrl", "");
374                         }
375                         set {
376                                 ViewState["ExpandImageUrl"] = value;
377                         }
378                 }
379
380                 [PersistenceMode (PersistenceMode.InnerProperty)]
381                 [NotifyParentProperty (true)]
382                 [DefaultValue (null)]
383                 [WebCategory ("Styles")]
384                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
385                 public Style HoverNodeStyle {
386                         get {
387                                 if (hoverNodeStyle == null) {
388                                         hoverNodeStyle = new Style();
389                                         if (IsTrackingViewState)
390                                                 hoverNodeStyle.TrackViewState();
391                                 }
392                                 return hoverNodeStyle;
393                         }
394                 }
395
396                 [DefaultValue (TreeViewImageSet.Custom)]
397                 public TreeViewImageSet ImageSet {
398                         get {
399                                 return (TreeViewImageSet)ViewState.GetInt ("ImageSet", (int)TreeViewImageSet.Custom);
400                         }
401                         set {
402                                 if (!Enum.IsDefined (typeof (TreeViewImageSet), value))
403                                         throw new ArgumentOutOfRangeException ();
404                                 ViewState["ImageSet"] = value;
405                         }
406                 }
407
408                 [PersistenceMode (PersistenceMode.InnerProperty)]
409                 [NotifyParentProperty (true)]
410                 [DefaultValue (null)]
411                 [WebCategory ("Styles")]
412                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
413                 public TreeNodeStyle LeafNodeStyle {
414                         get {
415                                 if (leafNodeStyle == null) {
416                                         leafNodeStyle = new TreeNodeStyle ();
417                                         if (IsTrackingViewState)
418                                                 leafNodeStyle.TrackViewState();
419                                 }
420                                 return leafNodeStyle;
421                         }
422                 }
423                 
424                 [DefaultValue (null)]
425                 [WebCategory ("Styles")]
426                 [PersistenceMode (PersistenceMode.InnerProperty)]
427                 [Editor ("System.Web.UI.Design.WebControls.TreeNodeStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
428                 public TreeNodeStyleCollection LevelStyles {
429                         get {
430                                 if (levelStyles == null) {
431                                         levelStyles = new TreeNodeStyleCollection ();
432                                         if (IsTrackingViewState)
433                                                 ((IStateManager)levelStyles).TrackViewState();
434                                 }
435                                 return levelStyles;
436                         }
437                 }
438
439                 [DefaultValue ("")]
440                 public string LineImagesFolder {
441                         get {
442                                 return ViewState.GetString ("LineImagesFolder", "");
443                         }
444                         set {
445                                 ViewState["LineImagesFolder"] = value;
446                         }
447                 }
448
449                 [DefaultValue (-1)]
450                 public int MaxDataBindDepth {
451                         get {
452                                 return ViewState.GetInt ("MaxDataBindDepth", -1);
453                         }
454                         set {
455                                 ViewState["MaxDataBindDepth"] = value;
456                         }
457                 }
458
459                 [DefaultValue (20)]
460                 public int NodeIndent {
461                         get {
462                                 return ViewState.GetInt ("NodeIndent", 20);
463                         }
464                         set {
465                                 ViewState["NodeIndent"] = value;
466                         }
467                 }
468                 
469                 [PersistenceMode (PersistenceMode.InnerProperty)]
470                 [Editor ("System.Web.UI.Design.WebControls.TreeNodeCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
471                 [DefaultValueAttribute (null)]
472                 [MergablePropertyAttribute (false)]
473                 public TreeNodeCollection Nodes {
474                         get {
475                                 if (nodes == null) {
476                                         nodes = new TreeNodeCollection (this);
477                                         if (IsTrackingViewState)
478                                                 ((IStateManager)nodes).TrackViewState();
479                                 }
480                                 return nodes;
481                         }
482                 }
483
484                 [PersistenceMode (PersistenceMode.InnerProperty)]
485                 [NotifyParentProperty (true)]
486                 [DefaultValue (null)]
487                 [WebCategory ("Styles")]
488                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
489                 public TreeNodeStyle NodeStyle {
490                         get {
491                                 if (nodeStyle == null) {
492                                         nodeStyle = new TreeNodeStyle ();
493                                         if (IsTrackingViewState)
494                                                 nodeStyle.TrackViewState();
495                                 }
496                                 return nodeStyle;
497                         }
498                 }
499                 
500                 [DefaultValue (false)]
501                 public bool NodeWrap {
502                         get {
503                                 return ViewState.GetBool ("NodeWrap", false);
504                         }
505                         set {
506                                 ViewState ["NodeWrap"] = value;
507                         }
508                 }
509
510                 [UrlProperty]
511                 [DefaultValue ("")]
512                 [WebSysDescription ("The url of the image to show for leaf nodes.")]
513                 [WebCategory ("Appearance")]
514                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
515                 public string NoExpandImageUrl {
516                         get {
517                                 return ViewState.GetString ("NoExpandImageUrl", "");
518                         }
519                         set {
520                                 ViewState ["NoExpandImageUrl"] = value;
521                         }
522                 }
523
524                 [PersistenceMode (PersistenceMode.InnerProperty)]
525                 [NotifyParentProperty (true)]
526                 [DefaultValue (null)]
527                 [WebCategory ("Styles")]
528                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
529                 public TreeNodeStyle ParentNodeStyle {
530                         get {
531                                 if (parentNodeStyle == null) {
532                                         parentNodeStyle = new TreeNodeStyle ();
533                                         if (IsTrackingViewState)
534                                                 parentNodeStyle.TrackViewState();
535                                 }
536                                 return parentNodeStyle;
537                         }
538                 }
539                 
540                 [DefaultValue ('/')]
541                 public char PathSeparator {
542                         get {
543                                 return ViewState.GetChar ("PathSeparator", '/');
544                         }
545                         set {
546                                 ViewState ["PathSeparator"] = value;
547                         }
548                 }
549
550                 [DefaultValue (true)]
551                 public bool PopulateNodesFromClient {
552                         get {
553                                 return ViewState.GetBool ("PopulateNodesFromClient", true);
554                         }
555                         set {
556                                 ViewState ["PopulateNodesFromClient"] = value;
557                         }
558                 }
559
560                 [PersistenceMode (PersistenceMode.InnerProperty)]
561                 [NotifyParentProperty (true)]
562                 [DefaultValue (null)]
563                 [WebCategory ("Styles")]
564                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
565                 public TreeNodeStyle RootNodeStyle {
566                         get {
567                                 if (rootNodeStyle == null) {
568                                         rootNodeStyle = new TreeNodeStyle ();
569                                         if (IsTrackingViewState)
570                                                 rootNodeStyle.TrackViewState();
571                                 }
572                                 return rootNodeStyle;
573                         }
574                 }
575                 
576                 [PersistenceMode (PersistenceMode.InnerProperty)]
577                 [NotifyParentProperty (true)]
578                 [DefaultValue (null)]
579                 [WebCategory ("Styles")]
580                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
581                 public TreeNodeStyle SelectedNodeStyle {
582                         get {
583                                 if (selectedNodeStyle == null) {
584                                         selectedNodeStyle = new TreeNodeStyle ();
585                                         if (IsTrackingViewState)
586                                                 selectedNodeStyle.TrackViewState();
587                                 }
588                                 return selectedNodeStyle;
589                         }
590                 }
591
592                 Style ControlLinkStyle {
593                         get {
594                                 if (controlLinkStyle == null) {
595                                         controlLinkStyle = new Style ();
596                                         controlLinkStyle.AlwaysRenderTextDecoration = true;
597                                 }
598                                 return controlLinkStyle;
599                         }
600                 }
601
602                 Style NodeLinkStyle {
603                         get {
604                                 if (nodeLinkStyle == null) {
605                                         nodeLinkStyle = new Style ();
606                                 }
607                                 return nodeLinkStyle;
608                         }
609                 }
610
611                 Style RootNodeLinkStyle {
612                         get {
613                                 if (rootNodeLinkStyle == null) {
614                                         rootNodeLinkStyle = new Style ();
615                                 }
616                                 return rootNodeLinkStyle;
617                         }
618                 }
619
620                 Style ParentNodeLinkStyle {
621                         get {
622                                 if (parentNodeLinkStyle == null) {
623                                         parentNodeLinkStyle = new Style ();
624                                 }
625                                 return parentNodeLinkStyle;
626                         }
627                 }
628
629                 Style SelectedNodeLinkStyle {
630                         get {
631                                 if (selectedNodeLinkStyle == null) {
632                                         selectedNodeLinkStyle = new Style ();
633                                 }
634                                 return selectedNodeLinkStyle;
635                         }
636                 }
637
638                 Style LeafNodeLinkStyle {
639                         get {
640                                 if (leafNodeLinkStyle == null) {
641                                         leafNodeLinkStyle = new Style ();
642                                 }
643                                 return leafNodeLinkStyle;
644                         }
645                 }
646
647                 Style HoverNodeLinkStyle {
648                         get {
649                                 if (hoverNodeLinkStyle == null) {
650                                         hoverNodeLinkStyle = new Style ();
651                                 }
652                                 return hoverNodeLinkStyle;
653                         }
654                 }
655                 
656                 [DefaultValue (TreeNodeTypes.None)]
657                 public TreeNodeTypes ShowCheckBoxes {
658                         get {
659                                 return (TreeNodeTypes)ViewState.GetInt ("ShowCheckBoxes", (int)TreeNodeTypes.None);
660                         }
661                         set {
662                                 if ((int) value > 7)
663                                         throw new ArgumentOutOfRangeException ();
664                                 ViewState ["ShowCheckBoxes"] = value;
665                         }
666                 }
667
668                 [DefaultValue (true)]
669                 public bool ShowExpandCollapse {
670                         get {
671                                 return ViewState.GetBool ("ShowExpandCollapse", true);
672                         }
673                         set {
674                                 ViewState ["ShowExpandCollapse"] = value;
675                         }
676                 }
677
678                 [DefaultValue (false)]
679                 public bool ShowLines {
680                         get {
681                                 return ViewState.GetBool ("ShowLines", false);
682                         }
683                         set {
684                                 ViewState ["ShowLines"] = value;
685                         }
686                 }
687
688                 [Localizable (true)]
689                 public string SkipLinkText
690                 {
691                         get {
692                                 return ViewState.GetString ("SkipLinkText", "Skip Navigation Links.");
693                         }
694                         set {
695                                 ViewState ["SkipLinkText"] = value;
696                         }
697                 }
698                 
699                 
700                 [Browsable (false)]
701                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
702                 public TreeNode SelectedNode {
703                         get { return selectedNode; }
704                 }
705
706                 [Browsable (false)]
707                 [DefaultValue ("")]
708                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
709                 public string SelectedValue {
710                         get { return selectedNode != null ? selectedNode.Value : ""; }
711                 }
712
713                 [DefaultValue ("")]
714                 public string Target {
715                         get {
716                                 return ViewState.GetString ("Target", "");
717                         }
718                         set {
719                                 ViewState ["Target"] = value;
720                         }
721                 }
722
723                 [MonoTODO ("why override?")]
724                 public override bool Visible 
725                 {
726                         get {
727                                 return base.Visible;
728                         }
729                         set {
730                                 base.Visible = value;
731                         }
732                 }
733                                 
734                 [Browsable (false)]
735                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
736                 public TreeNodeCollection CheckedNodes {
737                         get {
738                                 TreeNodeCollection col = new TreeNodeCollection ();
739                                 FindCheckedNodes (Nodes, col);
740                                 return col;
741                         }
742                 }
743                 
744                 void FindCheckedNodes (TreeNodeCollection nodeList, TreeNodeCollection result)
745                 {
746                         foreach (TreeNode node in nodeList) {
747                                 if (node.Checked) result.Add (node, false);
748                                 FindCheckedNodes (node.ChildNodes, result);
749                         }
750                 }
751                 
752                 public void ExpandAll ()
753                 {
754                         foreach (TreeNode node in Nodes)
755                                 node.ExpandAll ();
756                 }
757                 
758                 public void CollapseAll ()
759                 {
760                         foreach (TreeNode node in Nodes)
761                                 node.CollapseAll ();
762                 }
763                 
764                 public TreeNode FindNode (string valuePath)
765                 {
766                         if (valuePath == null) throw new ArgumentNullException ("valuePath");
767                         string[] path = valuePath.Split (PathSeparator);
768                         int n = 0;
769                         TreeNodeCollection col = Nodes;
770                         bool foundBranch = true;
771                         while (col.Count > 0 && foundBranch) {
772                                 foundBranch = false;
773                                 foreach (TreeNode node in col) {
774                                         if (node.Value == path [n]) {
775                                                 if (++n == path.Length) return node;
776                                                 col = node.ChildNodes;
777                                                 foundBranch = true;
778                                                 break;
779                                         }
780                                 }
781                         }
782                         return null;
783                 }
784                 
785                 ImageStyle GetImageStyle ()
786                 {
787                         if (ImageSet != TreeViewImageSet.Custom)
788                                 return (ImageStyle) imageStyles [ImageSet];
789                         else
790                                 return null;
791                 }
792                 
793                 protected override HtmlTextWriterTag TagKey {
794                         get { return HtmlTextWriterTag.Div; }
795                 }
796                 
797                 protected internal virtual TreeNode CreateNode ()
798                 {
799                         return new TreeNode (this);
800                 }
801                 
802                 public sealed override void DataBind ()
803                 {
804                         base.DataBind ();
805                 }
806                 
807                 protected void SetNodeDataBound (TreeNode node, bool dataBound)
808                 {
809                         node.SetDataBound (dataBound);
810                 }
811                 
812                 protected void SetNodeDataPath (TreeNode node, string dataPath)
813                 {
814                         node.SetDataPath (dataPath);
815                 }
816                 
817                 protected void SetNodeDataItem (TreeNode node, object dataItem)
818                 {
819                         node.SetDataItem (dataItem);
820                 }
821                 
822                 protected internal override void OnInit (EventArgs e)
823                 {
824                         base.OnInit (e);
825                 }
826                 
827                 internal void SetSelectedNode (TreeNode node, bool loading)
828                 {
829                         if (selectedNode == node) return;
830                         if (selectedNode != null)
831                                 selectedNode.SelectedFlag = false;
832                         selectedNode = node;
833                         if (!loading)
834                                 OnSelectedNodeChanged (new TreeNodeEventArgs (selectedNode));
835                 }
836                 
837                 internal void NotifyCheckChanged (TreeNode node)
838                 {
839                         OnTreeNodeCheckChanged (new TreeNodeEventArgs (node));
840                 }
841
842                 internal void NotifyExpandedChanged (TreeNode node)
843                 {
844                         if (node.Expanded.HasValue && node.Expanded.Value)
845                                 OnTreeNodeExpanded (new TreeNodeEventArgs (node));
846                         else if (node.Expanded.HasValue && node.IsParentNode)
847                                 OnTreeNodeCollapsed (new TreeNodeEventArgs (node));
848                 }
849
850                 internal void NotifyPopulateRequired (TreeNode node)
851                 {
852                         OnTreeNodePopulate (new TreeNodeEventArgs (node));
853                 }
854
855                 protected override void TrackViewState()
856                 {
857                         EnsureDataBound ();
858                         
859                         base.TrackViewState();
860                         if (hoverNodeStyle != null) {
861                                 hoverNodeStyle.TrackViewState();
862                         }
863                         if (leafNodeStyle != null) {
864                                 leafNodeStyle.TrackViewState();
865                         }
866                         if (levelStyles != null && levelStyles.Count > 0) {
867                                 ((IStateManager)levelStyles).TrackViewState();
868                         }
869                         if (nodeStyle != null) {
870                                 nodeStyle.TrackViewState();
871                         }
872                         if (parentNodeStyle != null) {
873                                 parentNodeStyle.TrackViewState();
874                         }
875                         if (rootNodeStyle != null) {
876                                 rootNodeStyle.TrackViewState();
877                         }
878                         if (selectedNodeStyle != null) {
879                                 selectedNodeStyle.TrackViewState();
880                         }
881                         if (dataBindings != null) {
882                                 ((IStateManager)dataBindings).TrackViewState ();
883                         }
884                         if (nodes != null) {
885                                 ((IStateManager)nodes).TrackViewState();;
886                         }
887                 }
888
889                 protected override object SaveViewState()
890                 {
891                         object[] states = new object [10];
892                         states[0] = base.SaveViewState();
893                         states[1] = (hoverNodeStyle == null ? null : hoverNodeStyle.SaveViewState());
894                         states[2] = (leafNodeStyle == null ? null : leafNodeStyle.SaveViewState());
895                         states[3] = (levelStyles == null ? null : ((IStateManager)levelStyles).SaveViewState());
896                         states[4] = (nodeStyle == null ? null : nodeStyle.SaveViewState());
897                         states[5] = (parentNodeStyle == null ? null : parentNodeStyle.SaveViewState());
898                         states[6] = (rootNodeStyle == null ? null : rootNodeStyle.SaveViewState());
899                         states[7] = (selectedNodeStyle == null ? null : selectedNodeStyle.SaveViewState());
900                         states[8] = (dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState());
901                         states[9] = (nodes == null ? null : ((IStateManager)nodes).SaveViewState());
902
903                         for (int i = states.Length - 1; i >= 0; i--) {
904                                 if (states [i] != null)
905                                         return states;
906                         }
907                         
908                         return null;
909                 }
910
911                 protected override void LoadViewState (object savedState)
912                 {
913                         if (savedState == null)
914                                 return;
915                                 
916                         object [] states = (object []) savedState;
917                         base.LoadViewState (states[0]);
918                         
919                         if (states[1] != null)
920                                 HoverNodeStyle.LoadViewState (states[1]);
921                         if (states[2] != null)
922                                 LeafNodeStyle.LoadViewState(states[2]);
923                         if (states[3] != null)
924                                 ((IStateManager)LevelStyles).LoadViewState(states[3]);
925                         if (states[4] != null)
926                                 NodeStyle.LoadViewState(states[4]);
927                         if (states[5] != null)
928                                 ParentNodeStyle.LoadViewState(states[5]);
929                         if (states[6] != null)
930                                 RootNodeStyle.LoadViewState(states[6]);
931                         if (states[7] != null)
932                                 SelectedNodeStyle.LoadViewState(states[7]);
933                         if (states[8] != null)
934                                 ((IStateManager)DataBindings).LoadViewState(states[8]);
935                         if (states[9] != null)
936                                 ((IStateManager)Nodes).LoadViewState(states[9]);
937                 }
938
939                 protected virtual void RaisePostBackEvent (string eventArgument)
940                 {
941                         ValidateEvent (UniqueID, eventArgument);
942                         string[] args = eventArgument.Split ('|');
943                         TreeNode node = FindNodeByPos (args[1]);
944                         if (node == null) return;
945                         
946                         if (args [0] == "sel")
947                                 HandleSelectEvent (node);
948                         else if (args [0] == "ec")
949                                 HandleExpandCollapseEvent (node);
950                 }
951                 
952                 void HandleSelectEvent (TreeNode node)
953                 {
954                         switch (node.SelectAction) {
955                                 case TreeNodeSelectAction.Select:
956                                         node.Select ();
957                                         break;
958                                 case TreeNodeSelectAction.Expand:
959                                         node.Expand ();
960                                         break;
961                                 case TreeNodeSelectAction.SelectExpand:
962                                         node.Select ();
963                                         node.Expand ();
964                                         break;
965                         }
966                 }
967                 
968                 void HandleExpandCollapseEvent (TreeNode node)
969                 {
970                         node.ToggleExpandState ();
971                 }
972                 
973                 protected virtual void RaisePostDataChangedEvent ()
974                 {
975                 }
976                 
977                 string callbackResult;
978                 protected virtual void RaiseCallbackEvent (string eventArgs)
979                 {
980                         RequiresDataBinding = true;
981                         EnsureDataBound ();
982                         
983                         TreeNode node = FindNodeByPos (eventArgs);
984                         ArrayList levelLines = new ArrayList ();
985                         TreeNode nd = node;
986                         while (nd != null) {
987                                 int childCount = nd.Parent != null ? nd.Parent.ChildNodes.Count : Nodes.Count;
988                                 levelLines.Insert (0, (nd.Index < childCount - 1) ? this : null);
989                                 nd = nd.Parent;
990                         }
991                         
992                         StringWriter sw = new StringWriter ();
993                         HtmlTextWriter writer = new HtmlTextWriter (sw);
994                         EnsureStylesPrepared ();
995                         
996                         node.Expanded = true;
997                         int num = node.ChildNodes.Count;
998                         for (int n=0; n<num; n++)
999                                 RenderNode (writer, node.ChildNodes [n], node.Depth + 1, levelLines, true, n<num-1);
1000                         
1001                         string res = sw.ToString ();
1002                         callbackResult = res != "" ? res : "*";
1003                 }
1004                 
1005                 protected virtual string GetCallbackResult ()
1006                 {
1007                         return callbackResult;
1008                 }
1009
1010                 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
1011                 {
1012                         RaisePostBackEvent (eventArgument);
1013                 }
1014                 
1015                 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
1016                 {
1017                         return LoadPostData (postDataKey, postCollection);
1018                 }
1019                 
1020                 void IPostBackDataHandler.RaisePostDataChangedEvent ()
1021                 {
1022                         RaisePostDataChangedEvent ();
1023                 }
1024                 
1025                 void ICallbackEventHandler.RaiseCallbackEvent (string eventArgs)
1026                 {
1027                         RaiseCallbackEvent (eventArgs);
1028                 }
1029                 
1030                 string ICallbackEventHandler.GetCallbackResult ()
1031                 {
1032                         return GetCallbackResult ();
1033                 }
1034
1035                 protected override ControlCollection CreateControlCollection ()
1036                 {
1037                         return new EmptyControlCollection (this);
1038                 }
1039                 
1040                 protected internal override void PerformDataBinding ()
1041                 {
1042                         base.PerformDataBinding ();
1043                         InitializeDataBindings ();
1044                         HierarchicalDataSourceView data = GetData ("");
1045                         if (data == null)
1046                                 return;
1047                         Nodes.Clear ();
1048                         IHierarchicalEnumerable e = data.Select ();
1049                         FillBoundChildrenRecursive (e, Nodes);
1050                 }
1051                 
1052                 void FillBoundChildrenRecursive (IHierarchicalEnumerable hEnumerable, TreeNodeCollection nodeCollection)
1053                 {
1054                         if (hEnumerable == null)
1055                                 return;                 
1056                         
1057                         foreach (object obj in hEnumerable) {
1058                                 IHierarchyData hdata = hEnumerable.GetHierarchyData (obj);
1059                                 TreeNode child = new TreeNode ();
1060                                 nodeCollection.Add (child);
1061                                 child.Bind (hdata);
1062                                 OnTreeNodeDataBound (new TreeNodeEventArgs (child));
1063
1064                                 if (MaxDataBindDepth >= 0 && child.Depth == MaxDataBindDepth)
1065                                         continue;
1066
1067                                 if (hdata == null || !hdata.HasChildren)
1068                                         continue;
1069
1070                                 IHierarchicalEnumerable e = hdata.GetChildren ();
1071                                 FillBoundChildrenRecursive (e, child.ChildNodes);
1072                         }
1073                 }
1074                 
1075                 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
1076                 {
1077                         bool res = false;
1078
1079                         if (EnableClientScript && PopulateNodesFromClient) {
1080                                 string states = postCollection [ClientID + "_PopulatedStates"];
1081                                 if (states != null) {
1082                                         foreach (string id in states.Split ('|')) {
1083                                                 if (String.IsNullOrEmpty(id))
1084                                                         continue;
1085                                                 TreeNode node = FindNodeByPos (id);
1086                                                 if (node != null && node.PopulateOnDemand && !node.Populated)
1087                                                         node.Populate();
1088                                         }
1089                                 }
1090                                 res = true;
1091                         }
1092
1093                         UnsetCheckStates (Nodes, postCollection);
1094                         SetCheckStates (postCollection);
1095                         
1096                         if (EnableClientScript) {
1097                                 string states = postCollection [ClientID + "_ExpandStates"];
1098                                 if (states != null) {
1099                                         string[] ids = states.Split ('|');
1100                                         UnsetExpandStates (Nodes, ids);
1101                                         SetExpandStates (ids);
1102                                 }
1103                                 else
1104                                         UnsetExpandStates (Nodes, new string[0]);
1105                                 res = true;
1106                         }
1107                         return res;
1108                 }
1109                 
1110                 protected internal override void OnPreRender (EventArgs e)
1111                 {
1112                         base.OnPreRender (e);
1113
1114                         if (Page != null) {
1115                                 if (Enabled)
1116                                         Page.RegisterRequiresPostBack (this);
1117                         
1118                                 if (EnableClientScript && !Page.ClientScript.IsClientScriptIncludeRegistered (typeof(TreeView), "TreeView.js")) {
1119                                         string url = Page.ClientScript.GetWebResourceUrl (typeof(TreeView), "TreeView.js");
1120                                         Page.ClientScript.RegisterClientScriptInclude (typeof(TreeView), "TreeView.js", url);
1121                                 }
1122                         }
1123                         
1124                         string ctree = ClientID + "_data";
1125                         string script = string.Format ("var {0} = new Object ();\n", ctree);
1126                         script += string.Format ("{0}.treeId = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (ClientID));
1127                         script += string.Format ("{0}.uid = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (UniqueID));
1128                         script += string.Format ("{0}.showImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (ShowExpandCollapse));
1129                         
1130                         if (ShowExpandCollapse) {
1131                                 ImageStyle imageStyle = GetImageStyle ();
1132                                 script += string.Format ("{0}.expandImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("plus", imageStyle)));
1133                                 script += string.Format ("{0}.collapseImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("minus", imageStyle)));
1134                                 if (PopulateNodesFromClient)
1135                                         script += string.Format ("{0}.noExpandImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("noexpand", imageStyle)));
1136                         }
1137
1138                         if (Page != null) {
1139                                 script += string.Format ("{0}.form = {1};\n", ctree, Page.theForm);
1140                                 script += string.Format (
1141 @"{0}.PopulateNode = function(nodeId) {{
1142         " + Page.WebFormScriptReference + @".__theFormPostData = """";
1143         " + Page.WebFormScriptReference + @".__theFormPostCollection = new Array();
1144         " + Page.WebFormScriptReference + @".WebForm_InitCallback();
1145         {1};
1146 }};
1147 ", ctree, Page.ClientScript.GetCallbackEventReference ("this.uid", "nodeId", "TreeView_PopulateCallback", "this.treeId + \" \" + nodeId", "TreeView_PopulateCallback", false));
1148                                 script += string.Format ("{0}.populateFromClient = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (PopulateNodesFromClient));
1149                                 script += string.Format ("{0}.expandAlt = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (true, null)));
1150                                 script += string.Format ("{0}.collapseAlt = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (false, null)));
1151
1152                                 if (!Page.IsPostBack) {
1153                                         SetNodesExpandedToDepthRecursive (Nodes);
1154                                 }
1155
1156                                 if (EnableClientScript) {
1157                                         Page.ClientScript.RegisterHiddenField (ClientID + "_ExpandStates", GetExpandStates ());
1158
1159                                         // Make sure the basic script infrastructure is rendered
1160                                         Page.ClientScript.RegisterWebFormClientScript ();
1161                                 }
1162
1163                                 if (EnableClientScript && PopulateNodesFromClient) {
1164                                         Page.ClientScript.RegisterHiddenField (ClientID + "_PopulatedStates", "|");
1165                                 }
1166
1167                                 EnsureStylesPrepared ();
1168
1169                                 if (hoverNodeStyle != null) {
1170                                         if (Page.Header == null)
1171                                                 throw new InvalidOperationException ("Using TreeView.HoverNodeStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
1172                                         RegisterStyle (HoverNodeStyle, HoverNodeLinkStyle);
1173                                         script += string.Format ("{0}.hoverClass = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (HoverNodeStyle.RegisteredCssClass));
1174                                         script += string.Format ("{0}.hoverLinkClass = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (HoverNodeLinkStyle.RegisteredCssClass));
1175                                 }
1176                                 
1177                                 Page.ClientScript.RegisterStartupScript (typeof(TreeView), this.UniqueID, script, true);
1178                         }
1179                 }
1180
1181                 void EnsureStylesPrepared () {
1182                         if (stylesPrepared)
1183                                 return;
1184                         stylesPrepared = true;
1185                         PrepareStyles ();
1186                 }
1187
1188                 void PrepareStyles () {
1189                         // The order in which styles are defined matters when more than one class
1190                         // is assigned to an element
1191                         ControlLinkStyle.CopyTextStylesFrom (ControlStyle);
1192                         RegisterStyle (ControlLinkStyle);
1193
1194                         if (nodeStyle != null)
1195                                 RegisterStyle (NodeStyle, NodeLinkStyle);
1196
1197                         if (rootNodeStyle != null)
1198                                 RegisterStyle (RootNodeStyle, RootNodeLinkStyle);
1199
1200                         if (parentNodeStyle != null)
1201                                 RegisterStyle (ParentNodeStyle, ParentNodeLinkStyle);
1202
1203                         if (leafNodeStyle != null)
1204                                 RegisterStyle (LeafNodeStyle, LeafNodeLinkStyle);
1205
1206
1207                         if (levelStyles != null && levelStyles.Count > 0) {
1208                                 levelLinkStyles = new List<Style> (levelStyles.Count);
1209                                 foreach (Style style in levelStyles) {
1210                                         Style linkStyle = new Style ();
1211                                         levelLinkStyles.Add (linkStyle);
1212                                         RegisterStyle (style, linkStyle);
1213                                 }
1214                         }
1215
1216                         if (selectedNodeStyle != null)
1217                                 RegisterStyle (SelectedNodeStyle, SelectedNodeLinkStyle);
1218                 }
1219
1220                 void SetNodesExpandedToDepthRecursive (TreeNodeCollection nodes) {
1221                         foreach (TreeNode node in nodes) {
1222                                 if (!node.Expanded.HasValue) {
1223                                         if (ExpandDepth < 0 || node.Depth < ExpandDepth)
1224                                                 node.Expanded = true;
1225                                 }
1226                                 SetNodesExpandedToDepthRecursive (node.ChildNodes);
1227                         }
1228                 }
1229
1230                 string IncrementStyleClassName () {
1231                         registeredStylesCounter++;
1232                         return ClientID + "_" + registeredStylesCounter;
1233                 }
1234
1235                 void RegisterStyle (Style baseStyle, Style linkStyle) {
1236                         linkStyle.CopyTextStylesFrom (baseStyle);
1237                         linkStyle.BorderStyle = BorderStyle.None;
1238                         baseStyle.Font.Reset ();
1239                         RegisterStyle (linkStyle);
1240                         RegisterStyle (baseStyle);
1241                 }
1242
1243                 void RegisterStyle (Style baseStyle) {
1244                         if (Page.Header == null)
1245                                 return;
1246                         string className = IncrementStyleClassName ().Trim ('_');
1247                         baseStyle.SetRegisteredCssClass (className);
1248                         Page.Header.StyleSheet.CreateStyleRule (baseStyle, this, "." + className);
1249                 }
1250                 
1251                 string GetBindingKey (string dataMember, int depth)
1252                 {
1253                         return dataMember + " " + depth;
1254                 }
1255                 
1256                 void InitializeDataBindings () {
1257                         if (dataBindings != null && dataBindings.Count > 0) {
1258                                 bindings = new Hashtable ();
1259                                 foreach (TreeNodeBinding bin in dataBindings) {
1260                                         string key = GetBindingKey (bin.DataMember, bin.Depth);
1261                                         if (!bindings.ContainsKey(key))
1262                                                 bindings [key] = bin;
1263                                 }
1264                         }
1265                         else
1266                                 bindings = null;
1267                 }
1268                 
1269                 internal TreeNodeBinding FindBindingForNode (string type, int depth)
1270                 {
1271                         if (bindings == null)
1272                                 return null;
1273                                 
1274                         TreeNodeBinding bin = (TreeNodeBinding) bindings [GetBindingKey (type, depth)];
1275                         if (bin != null) return bin;
1276                         
1277                         bin = (TreeNodeBinding) bindings [GetBindingKey (type, -1)];
1278                         if (bin != null) return bin;
1279                         
1280                         bin = (TreeNodeBinding) bindings [GetBindingKey ("", depth)];
1281                         if (bin != null) return bin;
1282                         
1283                         return (TreeNodeBinding) bindings [GetBindingKey ("", -1)];
1284                 }
1285                 
1286                 internal void DecorateNode(TreeNode node)
1287                 {
1288                         if (node == null)
1289                                 return;
1290                         
1291                         if (node.ImageUrl != null && node.ImageUrl.Length > 0)
1292                                 return;
1293
1294                         if (node.IsRootNode && rootNodeStyle != null) {
1295                                 node.ImageUrl = rootNodeStyle.ImageUrl;
1296                                 return;
1297                         }
1298                         if (node.IsParentNode && parentNodeStyle != null) {
1299                                 node.ImageUrl = parentNodeStyle.ImageUrl;
1300                                 return;
1301                         }
1302                         if (node.IsLeafNode && leafNodeStyle != null)
1303                                 node.ImageUrl = leafNodeStyle.ImageUrl;
1304                 }
1305                 
1306                 protected internal override void RenderContents (HtmlTextWriter writer)
1307                 {
1308                         SiteMapDataSource siteMap = GetDataSource () as SiteMapDataSource;
1309                         bool checkSitePath = IsBoundUsingDataSourceID && siteMap != null;
1310
1311                         if (checkSitePath) {
1312                                 IHierarchyData data = siteMap.Provider.CurrentNode;
1313                                 if (data != null)
1314                                         activeSiteMapPath = data.Path;
1315                         }
1316                         
1317                         ArrayList levelLines = new ArrayList ();
1318                         int num = Nodes.Count;
1319                         for (int n=0; n<num; n++)
1320                                 RenderNode (writer, Nodes [n], 0, levelLines, n>0, n<num-1);
1321                 }
1322                 
1323                 protected override void AddAttributesToRender(HtmlTextWriter writer)
1324                 {
1325                         base.AddAttributesToRender (writer);
1326                 }
1327                 
1328                 public override void RenderBeginTag (HtmlTextWriter writer)
1329                 {
1330                         if (SkipLinkText != "") {
1331                                 writer.AddAttribute (HtmlTextWriterAttribute.Href, "#" + ClientID + "_SkipLink");
1332                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1333
1334                                 Image img = new Image ();
1335                                 ClientScriptManager csm = new ClientScriptManager (null);
1336                                 img.ImageUrl = csm.GetWebResourceUrl (typeof (SiteMapPath), "transparent.gif");
1337                                 img.Attributes.Add ("height", "0");
1338                                 img.Attributes.Add ("width", "0");
1339                                 img.AlternateText = SkipLinkText;
1340                                 img.Render (writer);
1341
1342                                 writer.RenderEndTag ();
1343                         }
1344                         base.RenderBeginTag (writer);
1345                 }
1346                 
1347                 public override void RenderEndTag (HtmlTextWriter writer)
1348                 {
1349                         base.RenderEndTag (writer);
1350
1351                         if (SkipLinkText != "") {
1352                                 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_SkipLink");
1353                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1354                                 writer.RenderEndTag ();
1355                         }
1356                 }
1357                 
1358                 void RenderNode (HtmlTextWriter writer, TreeNode node, int level, ArrayList levelLines, bool hasPrevious, bool hasNext)
1359                 {
1360                         DecorateNode(node);
1361                         
1362                         string nodeImage;
1363                         bool clientExpand = EnableClientScript && Events [TreeNodeCollapsedEvent] == null && Events [TreeNodeExpandedEvent] == null;
1364                         ImageStyle imageStyle = GetImageStyle ();
1365                         bool renderChildNodes = node.Expanded.HasValue && node.Expanded.Value;
1366                         
1367                         if (clientExpand && !renderChildNodes)
1368                                 renderChildNodes = (!node.PopulateOnDemand || node.Populated);
1369                                 
1370                         bool hasChildNodes;
1371                         
1372                         if (renderChildNodes)
1373                                 hasChildNodes = node.ChildNodes.Count > 0;
1374                         else
1375                                 hasChildNodes = (node.PopulateOnDemand && !node.Populated) || node.ChildNodes.Count > 0;
1376                                 
1377                         writer.AddAttribute ("cellpadding", "0", false);
1378                         writer.AddAttribute ("cellspacing", "0", false);
1379                         writer.AddStyleAttribute ("border-width", "0");
1380                         writer.RenderBeginTag (HtmlTextWriterTag.Table);
1381
1382                         Unit nodeSpacing = GetNodeSpacing (node);
1383
1384                         if (nodeSpacing != Unit.Empty && (node.Depth > 0 || node.Index > 0))
1385                                 RenderMenuItemSpacing (writer, nodeSpacing);
1386                         
1387                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1388                         
1389                         // Vertical lines from previous levels
1390
1391                         nodeImage = GetNodeImageUrl ("i", imageStyle);
1392                         for (int n=0; n<level; n++) {
1393                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1394                                 writer.AddStyleAttribute ("width", NodeIndent + "px");
1395                                 writer.AddStyleAttribute ("height", "1px");
1396                                 writer.RenderBeginTag (HtmlTextWriterTag.Div);
1397                                 if (ShowLines && levelLines [n] != null) {
1398                                         writer.AddAttribute ("src", nodeImage);
1399                                         writer.AddAttribute (HtmlTextWriterAttribute.Alt, "", false);
1400                                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1401                                         writer.RenderEndTag ();
1402                                 }
1403                                 writer.RenderEndTag ();
1404                                 writer.RenderEndTag (); // TD
1405                         }
1406                         
1407                         // Node image + line
1408                         
1409                         if (ShowExpandCollapse || ShowLines) {
1410                                 bool buttonImage = false;
1411                                 string tooltip = "";
1412                                 string shape = "";
1413                                 
1414                                 if (ShowLines) {
1415                                         if (hasPrevious && hasNext) shape = "t";
1416                                         else if (hasPrevious && !hasNext) shape = "l";
1417                                         else if (!hasPrevious && hasNext) shape = "r";
1418                                         else shape = "dash";
1419                                 }
1420                                 
1421                                 if (ShowExpandCollapse) {
1422                                         if (hasChildNodes) {
1423                                                 buttonImage = true;
1424                                                 if (node.Expanded.HasValue && node.Expanded.Value) shape += "minus";
1425                                                 else shape += "plus";
1426                                                 tooltip = GetNodeImageToolTip (!(node.Expanded.HasValue && node.Expanded.Value), node.Text);
1427                                         } else if (!ShowLines)
1428                                                 shape = "noexpand";
1429                                 }
1430
1431                                 if (shape != "") {
1432                                         nodeImage = GetNodeImageUrl (shape, imageStyle);
1433                                         writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1434                                         
1435                                         if (buttonImage) {
1436                                                 if (!clientExpand || (!PopulateNodesFromClient && node.PopulateOnDemand && !node.Populated))
1437                                                         writer.AddAttribute ("href", GetClientEvent (node, "ec"));
1438                                                 else
1439                                                         writer.AddAttribute ("href", GetClientExpandEvent(node));
1440                                                 writer.RenderBeginTag (HtmlTextWriterTag.A);    // Anchor
1441                                         }
1442
1443                                         writer.AddAttribute ("alt", tooltip);
1444
1445                                         if (buttonImage && clientExpand)
1446                                                 writer.AddAttribute ("id", GetNodeClientId (node, "img"));
1447                                         writer.AddAttribute ("src", nodeImage);
1448                                         if (buttonImage)
1449                                                 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1450                                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1451                                         writer.RenderEndTag ();
1452                                         
1453                                         if (buttonImage)
1454                                                 writer.RenderEndTag ();         // Anchor
1455
1456                                         writer.RenderEndTag ();         // TD
1457                                 }
1458                         }
1459                         
1460                         // Node icon
1461                         
1462                         string imageUrl = node.ImageUrl.Length > 0 ? ResolveClientUrl (node.ImageUrl) : null;
1463                         if (String.IsNullOrEmpty (imageUrl) && imageStyle != null) {
1464                                 if (imageStyle.RootIcon != null && node.IsRootNode)
1465                                         imageUrl = GetNodeIconUrl (imageStyle.RootIcon);
1466                                 else if (imageStyle.ParentIcon != null && node.IsParentNode)
1467                                         imageUrl = GetNodeIconUrl (imageStyle.ParentIcon);
1468                                 else if (imageStyle.LeafIcon != null && node.IsLeafNode)
1469                                         imageUrl = GetNodeIconUrl (imageStyle.LeafIcon);
1470                         }
1471                         
1472                         if (level < LevelStyles.Count && LevelStyles [level].ImageUrl != null)
1473                                 imageUrl = ResolveClientUrl (LevelStyles [level].ImageUrl);
1474                         
1475                         if (!String.IsNullOrEmpty (imageUrl)) {
1476                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1477                                 BeginNodeTag (writer, node, clientExpand);
1478                                 writer.AddAttribute ("src", imageUrl);
1479                                 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1480                                 writer.AddAttribute ("alt", node.ImageToolTip);
1481                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1482                                 writer.RenderEndTag (); // IMG
1483                                 writer.RenderEndTag (); // style tag
1484                                 writer.RenderEndTag (); // TD
1485                         }
1486
1487                         if (!NodeWrap)
1488                                 writer.AddStyleAttribute ("white-space", "nowrap");
1489
1490                         bool nodeIsSelected = node == SelectedNode && selectedNodeStyle != null;
1491                         if (!nodeIsSelected && selectedNodeStyle != null) {
1492                                 if (!String.IsNullOrEmpty (activeSiteMapPath))
1493                                         nodeIsSelected = String.Compare (activeSiteMapPath,
1494                                                                          node.NavigateUrl,
1495                                                                          HttpRuntime.CaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) == 0;
1496                         }
1497                         
1498                         AddNodeStyle (writer, node, level, nodeIsSelected);
1499                         if (EnableClientScript) {
1500                                 writer.AddAttribute ("onmouseout", "TreeView_UnhoverNode(this)", false);
1501                                 writer.AddAttribute ("onmouseover", "TreeView_HoverNode('" + ClientID + "', this)");
1502                         }
1503                         writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1504                         
1505                         // Checkbox
1506                         
1507                         if (node.ShowCheckBoxInternal) {
1508                                 writer.AddAttribute ("name", ClientID + "_cs_" + node.Path);
1509                                 writer.AddAttribute ("type", "checkbox", false);
1510                                 writer.AddAttribute ("title", node.Text);
1511                                 if (node.Checked) writer.AddAttribute ("checked", "checked", false);
1512                                 writer.RenderBeginTag (HtmlTextWriterTag.Input);        // INPUT
1513                                 writer.RenderEndTag (); // INPUT
1514                         }
1515                         
1516                         // Text
1517                         
1518                         node.BeginRenderText (writer);
1519                         
1520                         if (clientExpand)
1521                                 writer.AddAttribute ("id", GetNodeClientId (node, "txt"));
1522                         AddNodeLinkStyle (writer, node, level, nodeIsSelected);
1523                         BeginNodeTag (writer, node, clientExpand);
1524                         writer.Write (node.Text);
1525                         writer.RenderEndTag (); // style tag
1526                         
1527                         node.EndRenderText (writer);
1528                         
1529                         writer.RenderEndTag (); // TD
1530                         
1531                         writer.RenderEndTag (); // TR
1532
1533                         if (nodeSpacing != Unit.Empty)
1534                                 RenderMenuItemSpacing (writer, nodeSpacing);
1535                         
1536                         writer.RenderEndTag (); // TABLE
1537                         
1538                         // Children
1539                         
1540                         if (hasChildNodes) {
1541                                 if (level >= levelLines.Count) {
1542                                         if (hasNext)
1543                                                 levelLines.Add (this);
1544                                         else
1545                                                 levelLines.Add (null);
1546                                 } else {
1547                                         if (hasNext)
1548                                                 levelLines [level] = this;
1549                                         else
1550                                                 levelLines [level] = null;
1551                                 }
1552                                 
1553                                 if (clientExpand) {
1554                                         if (!(node.Expanded.HasValue && node.Expanded.Value))
1555                                                 writer.AddStyleAttribute ("display", "none");
1556                                         else
1557                                                 writer.AddStyleAttribute ("display", "block");
1558                                         writer.AddAttribute ("id", GetNodeClientId (node, null));
1559                                         writer.RenderBeginTag (HtmlTextWriterTag.Span);
1560                                         
1561                                         if (renderChildNodes) {
1562                                                 AddChildrenPadding (writer, node);
1563                                                 int num = node.ChildNodes.Count;
1564                                                 for (int n=0; n<num; n++)
1565                                                         RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1566                                                 if (hasNext)
1567                                                         AddChildrenPadding (writer, node);
1568                                         }
1569                                         writer.RenderEndTag (); // SPAN
1570                                 } else if (renderChildNodes) {
1571                                         AddChildrenPadding (writer, node);
1572                                         int num = node.ChildNodes.Count;
1573                                         for (int n=0; n<num; n++)
1574                                                 RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1575                                         if (hasNext)
1576                                                 AddChildrenPadding (writer, node);
1577                                 }
1578                         }
1579                 }
1580
1581                 void AddChildrenPadding (HtmlTextWriter writer, TreeNode node)
1582                 {
1583                         int level = node.Depth;
1584                         Unit cnp = Unit.Empty;
1585                         
1586                         if (levelStyles != null && level < levelStyles.Count)
1587                                 cnp = levelStyles [level].ChildNodesPadding;
1588                         if (cnp.IsEmpty && nodeStyle != null)
1589                                 cnp = nodeStyle.ChildNodesPadding;
1590                         
1591                         double value;
1592                         if (cnp.IsEmpty || (value = cnp.Value) == 0 || cnp.Type != UnitType.Pixel)
1593                                 return;
1594
1595                         writer.RenderBeginTag (HtmlTextWriterTag.Table);
1596                         writer.AddAttribute ("height", ((int) value).ToString (), false);
1597                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1598                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
1599                         writer.RenderEndTag (); // td
1600                         writer.RenderEndTag (); // tr
1601                         writer.RenderEndTag (); // table
1602                 }
1603                 
1604                 void RenderMenuItemSpacing (HtmlTextWriter writer, Unit itemSpacing) {
1605                         writer.AddStyleAttribute ("height", itemSpacing.ToString ());
1606                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1607                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
1608                         writer.RenderEndTag ();
1609                         writer.RenderEndTag ();
1610                 }
1611
1612                 Unit GetNodeSpacing (TreeNode node) {
1613                         if (node.Selected && selectedNodeStyle != null && selectedNodeStyle.NodeSpacing != Unit.Empty) {
1614                                 return selectedNodeStyle.NodeSpacing;
1615                         }
1616
1617                         if (levelStyles != null && node.Depth < levelStyles.Count && levelStyles [node.Depth].NodeSpacing != Unit.Empty) {
1618                                 return levelStyles [node.Depth].NodeSpacing;
1619                         }
1620
1621                         if (node.IsLeafNode) {
1622                                 if (leafNodeStyle != null && leafNodeStyle.NodeSpacing != Unit.Empty)
1623                                         return leafNodeStyle.NodeSpacing;
1624                         }
1625                         else if (node.IsRootNode) {
1626                                 if (rootNodeStyle != null && rootNodeStyle.NodeSpacing != Unit.Empty)
1627                                         return rootNodeStyle.NodeSpacing;
1628                         }
1629                         else if (node.IsParentNode) {
1630                                 if (parentNodeStyle != null && parentNodeStyle.NodeSpacing != Unit.Empty)
1631                                         return parentNodeStyle.NodeSpacing;
1632                         }
1633
1634                         if (nodeStyle != null)
1635                                 return nodeStyle.NodeSpacing;
1636                         else
1637                                 return Unit.Empty;
1638                 }
1639
1640                 void AddNodeStyle (HtmlTextWriter writer, TreeNode node, int level, bool nodeIsSelected)
1641                 {
1642                         TreeNodeStyle style = new TreeNodeStyle ();
1643                         if (Page.Header != null) {
1644                                 // styles are registered
1645                                 if (nodeStyle != null) {
1646                                         style.AddCssClass (nodeStyle.CssClass);
1647                                         style.AddCssClass (nodeStyle.RegisteredCssClass);
1648                                 }
1649                                 if (node.IsLeafNode) {
1650                                         if (leafNodeStyle != null) {
1651                                                 style.AddCssClass (leafNodeStyle.CssClass);
1652                                                 style.AddCssClass (leafNodeStyle.RegisteredCssClass);
1653                                         }
1654                                 } else if (node.IsRootNode) {
1655                                         if (rootNodeStyle != null) {
1656                                                 style.AddCssClass (rootNodeStyle.CssClass);
1657                                                 style.AddCssClass (rootNodeStyle.RegisteredCssClass);
1658                                         }
1659                                 } else if (node.IsParentNode) {
1660                                         if (parentNodeStyle != null) {
1661                                                 style.AddCssClass (parentNodeStyle.CssClass);
1662                                                 style.AddCssClass (parentNodeStyle.RegisteredCssClass);
1663                                         }
1664                                 }
1665                                 if (levelStyles != null && levelStyles.Count > level) {
1666                                         style.AddCssClass (levelStyles [level].CssClass);
1667                                         style.AddCssClass (levelStyles [level].RegisteredCssClass);
1668                                 }
1669                                 
1670                                 if (nodeIsSelected) {
1671                                         style.AddCssClass (selectedNodeStyle.CssClass);
1672                                         style.AddCssClass (selectedNodeStyle.RegisteredCssClass);
1673                                 }
1674                         } else {
1675                                 // styles are not registered
1676                                 if (nodeStyle != null) {
1677                                         style.CopyFrom (nodeStyle);
1678                                 }
1679                                 if (node.IsLeafNode) {
1680                                         if (leafNodeStyle != null) {
1681                                                 style.CopyFrom (leafNodeStyle);
1682                                         }
1683                                 }
1684                                 else if (node.IsRootNode) {
1685                                         if (rootNodeStyle != null) {
1686                                                 style.CopyFrom (rootNodeStyle);
1687                                         }
1688                                 }
1689                                 else if (node.IsParentNode) {
1690                                         if (parentNodeStyle != null) {
1691                                                 style.CopyFrom (parentNodeStyle);
1692                                         }
1693                                 }
1694                                 if (levelStyles != null && levelStyles.Count > level) {
1695                                         style.CopyFrom (levelStyles [level]);
1696                                 }
1697                                 
1698                                 if (nodeIsSelected) {
1699                                         style.CopyFrom (selectedNodeStyle);
1700                                 }
1701                         }
1702                         style.AddAttributesToRender (writer);
1703                 }
1704
1705                 void AddNodeLinkStyle (HtmlTextWriter writer, TreeNode node, int level, bool nodeIsSelected)
1706                 {
1707                         Style style = new Style ();
1708                         if (Page.Header != null) {
1709                                 // styles are registered
1710                                 style.AddCssClass (ControlLinkStyle.RegisteredCssClass);
1711
1712                                 if (nodeStyle != null) {
1713                                         style.AddCssClass (nodeLinkStyle.CssClass);
1714                                         style.AddCssClass (nodeLinkStyle.RegisteredCssClass);
1715                                 }
1716                                 if (node.IsLeafNode) {
1717                                         if (leafNodeStyle != null) {
1718                                                 style.AddCssClass (leafNodeLinkStyle.CssClass);
1719                                                 style.AddCssClass (leafNodeLinkStyle.RegisteredCssClass);
1720                                         }
1721                                 }
1722                                 else if (node.IsRootNode) {
1723                                         if (rootNodeStyle != null) {
1724                                                 style.AddCssClass (rootNodeLinkStyle.CssClass);
1725                                                 style.AddCssClass (rootNodeLinkStyle.RegisteredCssClass);
1726                                         }
1727                                 }
1728                                 else if (node.IsParentNode) {
1729                                         if (parentNodeStyle != null) {
1730                                                 style.AddCssClass (parentNodeLinkStyle.CssClass);
1731                                                 style.AddCssClass (parentNodeLinkStyle.RegisteredCssClass);
1732                                         }
1733                                 }
1734                                 if (levelStyles != null && levelStyles.Count > level) {
1735                                         style.AddCssClass (levelLinkStyles [level].CssClass);
1736                                         style.AddCssClass (levelLinkStyles [level].RegisteredCssClass);
1737                                 }
1738                                 if (nodeIsSelected) {
1739                                         style.AddCssClass (selectedNodeLinkStyle.CssClass);
1740                                         style.AddCssClass (selectedNodeLinkStyle.RegisteredCssClass);
1741                                 }
1742                         }
1743                         else {
1744                                 // styles are not registered
1745                                 style.CopyFrom (ControlLinkStyle);
1746                                 if (nodeStyle != null) {
1747                                         style.CopyFrom (nodeLinkStyle);
1748                                 }
1749                                 if (node.IsLeafNode) {
1750                                         if (node.IsLeafNode && leafNodeStyle != null) {
1751                                                 style.CopyFrom (leafNodeLinkStyle);
1752                                         }
1753                                 }
1754                                 else if (node.IsRootNode) {
1755                                         if (node.IsRootNode && rootNodeStyle != null) {
1756                                                 style.CopyFrom (rootNodeLinkStyle);
1757                                         }
1758                                 }
1759                                 else if (node.IsParentNode) {
1760                                         if (node.IsParentNode && parentNodeStyle != null) {
1761                                                 style.CopyFrom (parentNodeLinkStyle);
1762                                         }
1763                                 }
1764                                 if (levelStyles != null && levelStyles.Count > level) {
1765                                         style.CopyFrom (levelLinkStyles [level]);
1766                                 }
1767                                 if (nodeIsSelected) {
1768                                         style.CopyFrom (selectedNodeLinkStyle);
1769                                 }
1770                                 style.AlwaysRenderTextDecoration = true;
1771                         }
1772                         style.AddAttributesToRender (writer);
1773                 }
1774
1775                 void BeginNodeTag (HtmlTextWriter writer, TreeNode node, bool clientExpand)
1776                 {
1777                         if(node.ToolTip.Length>0)
1778                                 writer.AddAttribute ("title", node.ToolTip);
1779
1780                         if (node.NavigateUrl != "") {
1781                                 string target = node.Target.Length > 0 ? node.Target : Target;
1782 #if TARGET_J2EE
1783                                 string navUrl = ResolveClientUrl (node.NavigateUrl, String.Compare (target, "_blank", StringComparison.InvariantCultureIgnoreCase) != 0);
1784 #else
1785                                 string navUrl = ResolveClientUrl (node.NavigateUrl);
1786 #endif
1787                                 writer.AddAttribute ("href", navUrl);
1788                                 if (target.Length > 0)
1789                                         writer.AddAttribute ("target", target);
1790                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1791                         }
1792                         else if (node.SelectAction != TreeNodeSelectAction.None) {
1793                                 if (node.SelectAction == TreeNodeSelectAction.Expand && clientExpand)
1794                                         writer.AddAttribute ("href", GetClientExpandEvent (node));
1795                                 else
1796                                         writer.AddAttribute ("href", GetClientEvent (node, "sel"));
1797                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1798                         }
1799                         else
1800                                 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1801                 }
1802                 
1803                 string GetNodeImageToolTip (bool expand, string txt) {
1804                         if (expand)  {
1805                                 if (ExpandImageToolTip != "")
1806                                         return String.Format (ExpandImageToolTip, txt);
1807                                 else if (txt != null)
1808                                         return "Expand " + txt;
1809                                 else
1810                                         return "Expand {0}";
1811                         } else {
1812                                 if (CollapseImageToolTip != "")
1813                                         return String.Format (CollapseImageToolTip, txt);
1814                                 else if (txt != null)
1815                                         return "Collapse " + txt;
1816                                 else
1817                                         return "Collapse {0}";
1818                         }
1819                 }
1820                 
1821                 string GetNodeClientId (TreeNode node, string sufix)
1822                 {
1823                         return ClientID + "_" + node.Path + (sufix != null ? "_" + sufix : "");
1824                 }
1825                                                         
1826                 string GetNodeImageUrl (string shape, ImageStyle imageStyle)
1827                 {
1828                         if (ShowLines) {
1829                                 if (!String.IsNullOrEmpty (LineImagesFolder))
1830                                         return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1831                         } else {
1832                                 if (imageStyle != null) {
1833                                         if (shape == "plus") {
1834                                                 if (!String.IsNullOrEmpty (imageStyle.Expand))
1835                                                         return GetNodeIconUrl (imageStyle.Expand);
1836                                         }
1837                                         else if (shape == "minus") {
1838                                                 if (!String.IsNullOrEmpty (imageStyle.Collapse))
1839                                                         return GetNodeIconUrl (imageStyle.Collapse);
1840                                         }
1841                                         else if (shape == "noexpand") {
1842                                                 if (!String.IsNullOrEmpty (imageStyle.NoExpand))
1843                                                         return GetNodeIconUrl (imageStyle.NoExpand);
1844                                         }
1845                                 }
1846                                 else {
1847                                         if (shape == "plus") {
1848                                                 if (!String.IsNullOrEmpty (ExpandImageUrl))
1849                                                         return ResolveClientUrl (ExpandImageUrl);
1850                                         }
1851                                         else if (shape == "minus") {
1852                                                 if (!String.IsNullOrEmpty (CollapseImageUrl))
1853                                                         return ResolveClientUrl (CollapseImageUrl);
1854                                         }
1855                                         else if (shape == "noexpand") {
1856                                                 if (!String.IsNullOrEmpty (NoExpandImageUrl))
1857                                                         return ResolveClientUrl (NoExpandImageUrl);
1858                                         }
1859                                 }
1860                                 if (!String.IsNullOrEmpty (LineImagesFolder))
1861                                         return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1862                         }
1863                         return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), "TreeView_" + shape + ".gif");
1864                 }
1865                 
1866                 string GetNodeIconUrl (string icon)
1867                 {
1868                         return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), icon + ".gif");
1869                 }
1870                 
1871                 string GetClientEvent (TreeNode node, string ev)
1872                 {
1873                         return Page.ClientScript.GetPostBackClientHyperlink (this, ev + "|" + node.Path, true);
1874                 }
1875                 
1876                 string GetClientExpandEvent (TreeNode node)
1877                 {
1878                         return "javascript:TreeView_ToggleExpand ('" + ClientID + "', '" + node.Path + "')";
1879                 }
1880                 
1881                 TreeNode FindNodeByPos (string path)
1882                 {
1883                         string[] indexes = path.Split ('_');
1884                         TreeNode node = null;
1885                         
1886                         foreach (string index in indexes) {
1887                                 int i = int.Parse (index);
1888                                 if (node == null) {
1889                                         if (i >= Nodes.Count) return null;
1890                                         node = Nodes [i];
1891                                 } else {
1892                                         if (i >= node.ChildNodes.Count) return null;
1893                                         node = node.ChildNodes [i];
1894                                 }
1895                         }
1896                         return node;
1897                 }
1898                 
1899                 void UnsetCheckStates (TreeNodeCollection col, NameValueCollection states)
1900                 {
1901                         foreach (TreeNode node in col) {
1902                                 if (node.ShowCheckBoxInternal && node.Checked) {
1903                                         if (states == null || states [ClientID + "_cs_" + node.Path] == null)
1904                                                 node.Checked = false;
1905                                 }
1906                                 if (node.HasChildData)
1907                                         UnsetCheckStates (node.ChildNodes, states);
1908                         }
1909                 }
1910                 
1911                 void SetCheckStates (NameValueCollection states)
1912                 {
1913                         if (states == null)
1914                                 return;
1915
1916                         string keyPrefix = ClientID + "_cs_";
1917                         foreach (string key in states) {
1918                                 if (key.StartsWith (keyPrefix, StringComparison.Ordinal)) {
1919                                         string id = key.Substring (keyPrefix.Length);
1920                                         TreeNode node = FindNodeByPos (id);
1921                                         if (node != null && !node.Checked)
1922                                                 node.Checked = true;
1923                                 }
1924                         }
1925                 }
1926                 
1927                 void UnsetExpandStates (TreeNodeCollection col, string[] states)
1928                 {
1929                         foreach (TreeNode node in col) {
1930                                 if (node.Expanded.HasValue && node.Expanded.Value) {
1931                                         bool expand = (Array.IndexOf (states, node.Path) != -1);
1932                                         if (!expand) node.Expanded = false;
1933                                 }
1934                                 if (node.HasChildData)
1935                                         UnsetExpandStates (node.ChildNodes, states);
1936                         }
1937                 }
1938                 
1939                 void SetExpandStates (string[] states)
1940                 {
1941                         foreach (string id in states) {
1942                                 if (id == null || id == "") continue;
1943                                 TreeNode node = FindNodeByPos (id);
1944                                 if (node != null)
1945                                         node.Expanded = true;
1946                         }
1947                 }
1948                 
1949                 string GetExpandStates ()
1950                 {
1951                         StringBuilder sb = new StringBuilder ("|");
1952                         
1953                         foreach (TreeNode node in Nodes)
1954                                 GetExpandStates (sb, node);
1955
1956                         return sb.ToString ();
1957                 }
1958                 
1959                 void GetExpandStates (StringBuilder sb, TreeNode node)
1960                 {
1961                         if (node.Expanded.HasValue && node.Expanded.Value) {
1962                                 sb.Append (node.Path);
1963                                 sb.Append ('|');
1964                         }
1965                         if (node.HasChildData) {
1966                                 foreach (TreeNode child in node.ChildNodes)
1967                                         GetExpandStates (sb, child);
1968                         }
1969                 }
1970         }
1971 }
1972
1973 #endif