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