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